ntdll: Move the file read/write functions to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e9e5c95058
commit
888d66a237
|
@ -339,296 +339,6 @@ NTSTATUS FILE_GetNtStatus(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* FILE_AsyncReadService (INTERNAL)
|
|
||||||
*/
|
|
||||||
static NTSTATUS FILE_AsyncReadService( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
|
|
||||||
{
|
|
||||||
struct async_fileio_read *fileio = user;
|
|
||||||
int fd, needs_close, result;
|
|
||||||
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case STATUS_ALERTED: /* got some new data */
|
|
||||||
/* check to see if the data is ready (non-blocking) */
|
|
||||||
if ((status = unix_funcs->server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
|
|
||||||
&needs_close, NULL, NULL )))
|
|
||||||
break;
|
|
||||||
|
|
||||||
result = unix_funcs->virtual_locked_read(fd, &fileio->buffer[fileio->already], fileio->count-fileio->already);
|
|
||||||
if (needs_close) close( fd );
|
|
||||||
|
|
||||||
if (result < 0)
|
|
||||||
{
|
|
||||||
if (errno == EAGAIN || errno == EINTR)
|
|
||||||
status = STATUS_PENDING;
|
|
||||||
else /* check to see if the transfer is complete */
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
}
|
|
||||||
else if (result == 0)
|
|
||||||
{
|
|
||||||
status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileio->already += result;
|
|
||||||
if (fileio->already >= fileio->count || fileio->avail_mode)
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
else
|
|
||||||
status = STATUS_PENDING;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATUS_TIMEOUT:
|
|
||||||
case STATUS_IO_TIMEOUT:
|
|
||||||
if (fileio->already) status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (status != STATUS_PENDING)
|
|
||||||
{
|
|
||||||
iosb->u.Status = status;
|
|
||||||
iosb->Information = fileio->already;
|
|
||||||
release_fileio( &fileio->io );
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do a read call through the server */
|
|
||||||
static NTSTATUS server_read_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
|
|
||||||
IO_STATUS_BLOCK *io, void *buffer, ULONG size,
|
|
||||||
LARGE_INTEGER *offset, ULONG *key )
|
|
||||||
{
|
|
||||||
struct async_irp *async;
|
|
||||||
NTSTATUS status;
|
|
||||||
HANDLE wait_handle;
|
|
||||||
ULONG options;
|
|
||||||
|
|
||||||
if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), irp_completion, handle )))
|
|
||||||
return STATUS_NO_MEMORY;
|
|
||||||
|
|
||||||
async->buffer = buffer;
|
|
||||||
async->size = size;
|
|
||||||
|
|
||||||
SERVER_START_REQ( read )
|
|
||||||
{
|
|
||||||
req->async = server_async( handle, &async->io, event, apc, apc_context, io );
|
|
||||||
req->pos = offset ? offset->QuadPart : 0;
|
|
||||||
wine_server_set_reply( req, buffer, size );
|
|
||||||
status = unix_funcs->virtual_locked_server_call( req );
|
|
||||||
wait_handle = wine_server_ptr_handle( reply->wait );
|
|
||||||
options = reply->options;
|
|
||||||
if (wait_handle && status != STATUS_PENDING)
|
|
||||||
{
|
|
||||||
io->u.Status = status;
|
|
||||||
io->Information = wine_server_reply_size( reply );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
|
|
||||||
|
|
||||||
if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do a write call through the server */
|
|
||||||
static NTSTATUS server_write_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context,
|
|
||||||
IO_STATUS_BLOCK *io, const void *buffer, ULONG size,
|
|
||||||
LARGE_INTEGER *offset, ULONG *key )
|
|
||||||
{
|
|
||||||
struct async_irp *async;
|
|
||||||
NTSTATUS status;
|
|
||||||
HANDLE wait_handle;
|
|
||||||
ULONG options;
|
|
||||||
|
|
||||||
if (!(async = (struct async_irp *)alloc_fileio( sizeof(*async), irp_completion, handle )))
|
|
||||||
return STATUS_NO_MEMORY;
|
|
||||||
|
|
||||||
async->buffer = NULL;
|
|
||||||
async->size = 0;
|
|
||||||
|
|
||||||
SERVER_START_REQ( write )
|
|
||||||
{
|
|
||||||
req->async = server_async( handle, &async->io, event, apc, apc_context, io );
|
|
||||||
req->pos = offset ? offset->QuadPart : 0;
|
|
||||||
wine_server_add_data( req, buffer, size );
|
|
||||||
status = wine_server_call( req );
|
|
||||||
wait_handle = wine_server_ptr_handle( reply->wait );
|
|
||||||
options = reply->options;
|
|
||||||
if (wait_handle && status != STATUS_PENDING)
|
|
||||||
{
|
|
||||||
io->u.Status = status;
|
|
||||||
io->Information = reply->size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async );
|
|
||||||
|
|
||||||
if (wait_handle) status = wait_async( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), io );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct io_timeouts
|
|
||||||
{
|
|
||||||
int interval; /* max interval between two bytes */
|
|
||||||
int total; /* total timeout for the whole operation */
|
|
||||||
int end_time; /* absolute time of end of operation */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* retrieve the I/O timeouts to use for a given handle */
|
|
||||||
static NTSTATUS get_io_timeouts( HANDLE handle, enum server_fd_type type, ULONG count, BOOL is_read,
|
|
||||||
struct io_timeouts *timeouts )
|
|
||||||
{
|
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
|
||||||
|
|
||||||
timeouts->interval = timeouts->total = -1;
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case FD_TYPE_SERIAL:
|
|
||||||
{
|
|
||||||
/* GetCommTimeouts */
|
|
||||||
SERIAL_TIMEOUTS st;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
|
|
||||||
status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
|
|
||||||
IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
|
|
||||||
if (status) break;
|
|
||||||
|
|
||||||
if (is_read)
|
|
||||||
{
|
|
||||||
if (st.ReadIntervalTimeout)
|
|
||||||
timeouts->interval = st.ReadIntervalTimeout;
|
|
||||||
|
|
||||||
if (st.ReadTotalTimeoutMultiplier || st.ReadTotalTimeoutConstant)
|
|
||||||
{
|
|
||||||
timeouts->total = st.ReadTotalTimeoutConstant;
|
|
||||||
if (st.ReadTotalTimeoutMultiplier != MAXDWORD)
|
|
||||||
timeouts->total += count * st.ReadTotalTimeoutMultiplier;
|
|
||||||
}
|
|
||||||
else if (st.ReadIntervalTimeout == MAXDWORD)
|
|
||||||
timeouts->interval = timeouts->total = 0;
|
|
||||||
}
|
|
||||||
else /* write */
|
|
||||||
{
|
|
||||||
if (st.WriteTotalTimeoutMultiplier || st.WriteTotalTimeoutConstant)
|
|
||||||
{
|
|
||||||
timeouts->total = st.WriteTotalTimeoutConstant;
|
|
||||||
if (st.WriteTotalTimeoutMultiplier != MAXDWORD)
|
|
||||||
timeouts->total += count * st.WriteTotalTimeoutMultiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FD_TYPE_MAILSLOT:
|
|
||||||
if (is_read)
|
|
||||||
{
|
|
||||||
timeouts->interval = 0; /* return as soon as we got something */
|
|
||||||
SERVER_START_REQ( set_mailslot_info )
|
|
||||||
{
|
|
||||||
req->handle = wine_server_obj_handle( handle );
|
|
||||||
req->flags = 0;
|
|
||||||
if (!(status = wine_server_call( req )) &&
|
|
||||||
reply->read_timeout != TIMEOUT_INFINITE)
|
|
||||||
timeouts->total = reply->read_timeout / -10000;
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FD_TYPE_SOCKET:
|
|
||||||
case FD_TYPE_CHAR:
|
|
||||||
if (is_read) timeouts->interval = 0; /* return as soon as we got something */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (timeouts->total != -1) timeouts->end_time = NtGetTickCount() + timeouts->total;
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* retrieve the timeout for the next wait, in milliseconds */
|
|
||||||
static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG already )
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (timeouts->total != -1)
|
|
||||||
{
|
|
||||||
ret = timeouts->end_time - NtGetTickCount();
|
|
||||||
if (ret < 0) ret = 0;
|
|
||||||
}
|
|
||||||
if (already && timeouts->interval != -1)
|
|
||||||
{
|
|
||||||
if (ret == -1 || ret > timeouts->interval) ret = timeouts->interval;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* retrieve the avail_mode flag for async reads */
|
|
||||||
static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
|
|
||||||
{
|
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case FD_TYPE_SERIAL:
|
|
||||||
{
|
|
||||||
/* GetCommTimeouts */
|
|
||||||
SERIAL_TIMEOUTS st;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
|
|
||||||
status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
|
|
||||||
IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
|
|
||||||
if (status) break;
|
|
||||||
*avail_mode = (!st.ReadTotalTimeoutMultiplier &&
|
|
||||||
!st.ReadTotalTimeoutConstant &&
|
|
||||||
st.ReadIntervalTimeout == MAXDWORD);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FD_TYPE_MAILSLOT:
|
|
||||||
case FD_TYPE_SOCKET:
|
|
||||||
case FD_TYPE_CHAR:
|
|
||||||
*avail_mode = TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*avail_mode = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* register an async I/O for a file read; helper for NtReadFile */
|
|
||||||
static NTSTATUS register_async_file_read( HANDLE handle, HANDLE event,
|
|
||||||
PIO_APC_ROUTINE apc, void *apc_user,
|
|
||||||
IO_STATUS_BLOCK *iosb, void *buffer,
|
|
||||||
ULONG already, ULONG length, BOOL avail_mode )
|
|
||||||
{
|
|
||||||
struct async_fileio_read *fileio;
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
if (!(fileio = (struct async_fileio_read *)alloc_fileio( sizeof(*fileio), FILE_AsyncReadService, handle )))
|
|
||||||
return STATUS_NO_MEMORY;
|
|
||||||
|
|
||||||
fileio->already = already;
|
|
||||||
fileio->count = length;
|
|
||||||
fileio->buffer = buffer;
|
|
||||||
fileio->avail_mode = avail_mode;
|
|
||||||
|
|
||||||
SERVER_START_REQ( register_async )
|
|
||||||
{
|
|
||||||
req->type = ASYNC_TYPE_READ;
|
|
||||||
req->count = length;
|
|
||||||
req->async = server_async( handle, &fileio->io, event, apc, apc_user, iosb );
|
|
||||||
status = wine_server_call( req );
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* NtReadFile [NTDLL.@]
|
* NtReadFile [NTDLL.@]
|
||||||
|
@ -657,196 +367,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
|
||||||
PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
|
PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
|
||||||
PLARGE_INTEGER offset, PULONG key)
|
PLARGE_INTEGER offset, PULONG key)
|
||||||
{
|
{
|
||||||
int result, unix_handle, needs_close;
|
return unix_funcs->NtReadFile( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
|
||||||
unsigned int options;
|
|
||||||
struct io_timeouts timeouts;
|
|
||||||
NTSTATUS status, ret_status;
|
|
||||||
ULONG total = 0;
|
|
||||||
enum server_fd_type type;
|
|
||||||
ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
|
|
||||||
BOOL send_completion = FALSE, async_read, timeout_init_done = FALSE;
|
|
||||||
|
|
||||||
TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)\n",
|
|
||||||
hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
|
|
||||||
|
|
||||||
if (!io_status) return STATUS_ACCESS_VIOLATION;
|
|
||||||
|
|
||||||
status = unix_funcs->server_get_unix_fd( hFile, FILE_READ_DATA, &unix_handle,
|
|
||||||
&needs_close, &type, &options );
|
|
||||||
if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
|
|
||||||
|
|
||||||
if (!unix_funcs->virtual_check_buffer_for_write( buffer, length )) return STATUS_ACCESS_VIOLATION;
|
|
||||||
|
|
||||||
if (status == STATUS_BAD_DEVICE_TYPE)
|
|
||||||
return server_read_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
|
|
||||||
|
|
||||||
async_read = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
|
|
||||||
|
|
||||||
if (type == FD_TYPE_FILE)
|
|
||||||
{
|
|
||||||
if (async_read && (!offset || offset->QuadPart < 0))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
|
||||||
{
|
|
||||||
/* async I/O doesn't make sense on regular files */
|
|
||||||
while ((result = unix_funcs->virtual_locked_pread( unix_handle, buffer, length, offset->QuadPart )) == -1)
|
|
||||||
{
|
|
||||||
if (errno != EINTR)
|
|
||||||
{
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!async_read)
|
|
||||||
/* update file pointer position */
|
|
||||||
lseek( unix_handle, offset->QuadPart + result, SEEK_SET );
|
|
||||||
|
|
||||||
total = result;
|
|
||||||
status = (total || !length) ? STATUS_SUCCESS : STATUS_END_OF_FILE;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == FD_TYPE_SERIAL || type == FD_TYPE_DEVICE)
|
|
||||||
{
|
|
||||||
if (async_read && (!offset || offset->QuadPart < 0))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == FD_TYPE_SERIAL && async_read && length)
|
|
||||||
{
|
|
||||||
/* an asynchronous serial port read with a read interval timeout needs to
|
|
||||||
skip the synchronous read to make sure that the server starts the read
|
|
||||||
interval timer after the first read */
|
|
||||||
if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts ))) goto err;
|
|
||||||
if (timeouts.interval)
|
|
||||||
{
|
|
||||||
status = register_async_file_read( hFile, hEvent, apc, apc_user, io_status,
|
|
||||||
buffer, total, length, FALSE );
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if ((result = unix_funcs->virtual_locked_read( unix_handle, (char *)buffer + total, length - total )) >= 0)
|
|
||||||
{
|
|
||||||
total += result;
|
|
||||||
if (!result || total == length)
|
|
||||||
{
|
|
||||||
if (total)
|
|
||||||
{
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case FD_TYPE_FILE:
|
|
||||||
case FD_TYPE_CHAR:
|
|
||||||
case FD_TYPE_DEVICE:
|
|
||||||
status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
case FD_TYPE_SERIAL:
|
|
||||||
if (!length)
|
|
||||||
{
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
status = STATUS_PIPE_BROKEN;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
|
|
||||||
}
|
|
||||||
else if (errno != EAGAIN)
|
|
||||||
{
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
if (!total) status = FILE_GetNtStatus();
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (async_read)
|
|
||||||
{
|
|
||||||
BOOL avail_mode;
|
|
||||||
|
|
||||||
if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
|
|
||||||
goto err;
|
|
||||||
if (total && avail_mode)
|
|
||||||
{
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
status = register_async_file_read( hFile, hEvent, apc, apc_user, io_status,
|
|
||||||
buffer, total, length, avail_mode );
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
else /* synchronous read, wait for the fd to become ready */
|
|
||||||
{
|
|
||||||
struct pollfd pfd;
|
|
||||||
int ret, timeout;
|
|
||||||
|
|
||||||
if (!timeout_init_done)
|
|
||||||
{
|
|
||||||
timeout_init_done = TRUE;
|
|
||||||
if ((status = get_io_timeouts( hFile, type, length, TRUE, &timeouts )))
|
|
||||||
goto err;
|
|
||||||
if (hEvent) NtResetEvent( hEvent, NULL );
|
|
||||||
}
|
|
||||||
timeout = get_next_io_timeout( &timeouts, total );
|
|
||||||
|
|
||||||
pfd.fd = unix_handle;
|
|
||||||
pfd.events = POLLIN;
|
|
||||||
|
|
||||||
if (!timeout || !(ret = poll( &pfd, 1, timeout )))
|
|
||||||
{
|
|
||||||
if (total) /* return with what we got so far */
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
else
|
|
||||||
status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (ret == -1 && errno != EINTR)
|
|
||||||
{
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* will now restart the read */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
send_completion = cvalue != 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (needs_close) close( unix_handle );
|
|
||||||
if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && (!async_read || type == FD_TYPE_FILE)))
|
|
||||||
{
|
|
||||||
io_status->u.Status = status;
|
|
||||||
io_status->Information = total;
|
|
||||||
TRACE("= SUCCESS (%u)\n", total);
|
|
||||||
if (hEvent) NtSetEvent( hEvent, NULL );
|
|
||||||
if (apc && (!status || async_read)) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
|
|
||||||
(ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACE("= 0x%08x\n", status);
|
|
||||||
if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
ret_status = async_read && type == FD_TYPE_FILE && (status == STATUS_SUCCESS || status == STATUS_END_OF_FILE)
|
|
||||||
? STATUS_PENDING : status;
|
|
||||||
|
|
||||||
if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total, ret_status == STATUS_PENDING );
|
|
||||||
return ret_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -858,144 +379,11 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
|
||||||
PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
|
PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
|
||||||
ULONG length, PLARGE_INTEGER offset, PULONG key )
|
ULONG length, PLARGE_INTEGER offset, PULONG key )
|
||||||
{
|
{
|
||||||
int result, unix_handle, needs_close;
|
return unix_funcs->NtReadFileScatter( file, event, apc, apc_user, io_status,
|
||||||
unsigned int options;
|
segments, length, offset, key );
|
||||||
NTSTATUS status;
|
|
||||||
ULONG pos = 0, total = 0;
|
|
||||||
enum server_fd_type type;
|
|
||||||
ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
|
|
||||||
BOOL send_completion = FALSE;
|
|
||||||
|
|
||||||
TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
|
|
||||||
file, event, apc, apc_user, io_status, segments, length, offset, key);
|
|
||||||
|
|
||||||
if (!io_status) return STATUS_ACCESS_VIOLATION;
|
|
||||||
|
|
||||||
status = unix_funcs->server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
|
|
||||||
&needs_close, &type, &options );
|
|
||||||
if (status) return status;
|
|
||||||
|
|
||||||
if ((type != FD_TYPE_FILE) ||
|
|
||||||
(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
|
|
||||||
!(options & FILE_NO_INTERMEDIATE_BUFFERING))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (length)
|
|
||||||
{
|
|
||||||
if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
|
||||||
result = pread( unix_handle, (char *)segments->Buffer + pos,
|
|
||||||
min( length - pos, page_size - pos ), offset->QuadPart + total );
|
|
||||||
else
|
|
||||||
result = read( unix_handle, (char *)segments->Buffer + pos, min( length - pos, page_size - pos ) );
|
|
||||||
|
|
||||||
if (result == -1)
|
|
||||||
{
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!result) break;
|
|
||||||
total += result;
|
|
||||||
length -= result;
|
|
||||||
if ((pos += result) == page_size)
|
|
||||||
{
|
|
||||||
pos = 0;
|
|
||||||
segments++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total == 0) status = STATUS_END_OF_FILE;
|
|
||||||
|
|
||||||
send_completion = cvalue != 0;
|
|
||||||
|
|
||||||
if (needs_close) close( unix_handle );
|
|
||||||
|
|
||||||
io_status->u.Status = status;
|
|
||||||
io_status->Information = total;
|
|
||||||
TRACE("= 0x%08x (%u)\n", status, total);
|
|
||||||
if (event) NtSetEvent( event, NULL );
|
|
||||||
if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
|
|
||||||
(ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
|
|
||||||
if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total, TRUE );
|
|
||||||
|
|
||||||
return STATUS_PENDING;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (needs_close) close( unix_handle );
|
|
||||||
|
|
||||||
TRACE("= 0x%08x\n", status);
|
|
||||||
if (event) NtResetEvent( event, NULL );
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* FILE_AsyncWriteService (INTERNAL)
|
|
||||||
*/
|
|
||||||
static NTSTATUS FILE_AsyncWriteService( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status )
|
|
||||||
{
|
|
||||||
struct async_fileio_write *fileio = user;
|
|
||||||
int result, fd, needs_close;
|
|
||||||
enum server_fd_type type;
|
|
||||||
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case STATUS_ALERTED:
|
|
||||||
/* write some data (non-blocking) */
|
|
||||||
if ((status = unix_funcs->server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
|
|
||||||
&needs_close, &type, NULL )))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET))
|
|
||||||
result = send( fd, fileio->buffer, 0, 0 );
|
|
||||||
else
|
|
||||||
result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
|
|
||||||
|
|
||||||
if (needs_close) close( fd );
|
|
||||||
|
|
||||||
if (result < 0)
|
|
||||||
{
|
|
||||||
if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
|
|
||||||
else status = FILE_GetNtStatus();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileio->already += result;
|
|
||||||
status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATUS_TIMEOUT:
|
|
||||||
case STATUS_IO_TIMEOUT:
|
|
||||||
if (fileio->already) status = STATUS_SUCCESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (status != STATUS_PENDING)
|
|
||||||
{
|
|
||||||
iosb->u.Status = status;
|
|
||||||
iosb->Information = fileio->already;
|
|
||||||
release_fileio( &fileio->io );
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS set_pending_write( HANDLE device )
|
|
||||||
{
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
SERVER_START_REQ( set_serial_info )
|
|
||||||
{
|
|
||||||
req->handle = wine_server_obj_handle( device );
|
|
||||||
req->flags = SERIALINFO_PENDING_WRITE;
|
|
||||||
status = wine_server_call( req );
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* NtWriteFile [NTDLL.@]
|
* NtWriteFile [NTDLL.@]
|
||||||
|
@ -1025,223 +413,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
|
||||||
const void* buffer, ULONG length,
|
const void* buffer, ULONG length,
|
||||||
PLARGE_INTEGER offset, PULONG key)
|
PLARGE_INTEGER offset, PULONG key)
|
||||||
{
|
{
|
||||||
int result, unix_handle, needs_close;
|
return unix_funcs->NtWriteFile( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
|
||||||
unsigned int options;
|
|
||||||
struct io_timeouts timeouts;
|
|
||||||
NTSTATUS status, ret_status;
|
|
||||||
ULONG total = 0;
|
|
||||||
enum server_fd_type type;
|
|
||||||
ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
|
|
||||||
BOOL send_completion = FALSE, async_write, append_write = FALSE, timeout_init_done = FALSE;
|
|
||||||
LARGE_INTEGER offset_eof;
|
|
||||||
|
|
||||||
TRACE("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p)\n",
|
|
||||||
hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
|
|
||||||
|
|
||||||
if (!io_status) return STATUS_ACCESS_VIOLATION;
|
|
||||||
|
|
||||||
status = unix_funcs->server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
|
|
||||||
&needs_close, &type, &options );
|
|
||||||
if (status == STATUS_ACCESS_DENIED)
|
|
||||||
{
|
|
||||||
status = unix_funcs->server_get_unix_fd( hFile, FILE_APPEND_DATA, &unix_handle,
|
|
||||||
&needs_close, &type, &options );
|
|
||||||
append_write = TRUE;
|
|
||||||
}
|
|
||||||
if (status && status != STATUS_BAD_DEVICE_TYPE) return status;
|
|
||||||
|
|
||||||
async_write = !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT));
|
|
||||||
|
|
||||||
if (!unix_funcs->virtual_check_buffer_for_read( buffer, length ))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_USER_BUFFER;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == STATUS_BAD_DEVICE_TYPE)
|
|
||||||
return server_write_file( hFile, hEvent, apc, apc_user, io_status, buffer, length, offset, key );
|
|
||||||
|
|
||||||
if (type == FD_TYPE_FILE)
|
|
||||||
{
|
|
||||||
if (async_write &&
|
|
||||||
(!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (append_write)
|
|
||||||
{
|
|
||||||
offset_eof.QuadPart = FILE_WRITE_TO_END_OF_FILE;
|
|
||||||
offset = &offset_eof;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
|
||||||
{
|
|
||||||
off_t off = offset->QuadPart;
|
|
||||||
|
|
||||||
if (offset->QuadPart == FILE_WRITE_TO_END_OF_FILE)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (fstat( unix_handle, &st ) == -1)
|
|
||||||
{
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
off = st.st_size;
|
|
||||||
}
|
|
||||||
else if (offset->QuadPart < 0)
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* async I/O doesn't make sense on regular files */
|
|
||||||
while ((result = pwrite( unix_handle, buffer, length, off )) == -1)
|
|
||||||
{
|
|
||||||
if (errno != EINTR)
|
|
||||||
{
|
|
||||||
if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
|
|
||||||
else status = FILE_GetNtStatus();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!async_write)
|
|
||||||
/* update file pointer position */
|
|
||||||
lseek( unix_handle, off + result, SEEK_SET );
|
|
||||||
|
|
||||||
total = result;
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == FD_TYPE_SERIAL || type == FD_TYPE_DEVICE)
|
|
||||||
{
|
|
||||||
if (async_write &&
|
|
||||||
(!offset || (offset->QuadPart < 0 && offset->QuadPart != FILE_WRITE_TO_END_OF_FILE)))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
/* zero-length writes on sockets may not work with plain write(2) */
|
|
||||||
if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET))
|
|
||||||
result = send( unix_handle, buffer, 0, 0 );
|
|
||||||
else
|
|
||||||
result = write( unix_handle, (const char *)buffer + total, length - total );
|
|
||||||
|
|
||||||
if (result >= 0)
|
|
||||||
{
|
|
||||||
total += result;
|
|
||||||
if (total == length)
|
|
||||||
{
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */
|
|
||||||
}
|
|
||||||
else if (errno != EAGAIN)
|
|
||||||
{
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
if (!total)
|
|
||||||
{
|
|
||||||
if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER;
|
|
||||||
else status = FILE_GetNtStatus();
|
|
||||||
}
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (async_write)
|
|
||||||
{
|
|
||||||
struct async_fileio_write *fileio;
|
|
||||||
|
|
||||||
fileio = (struct async_fileio_write *)alloc_fileio( sizeof(*fileio), FILE_AsyncWriteService, hFile );
|
|
||||||
if (!fileio)
|
|
||||||
{
|
|
||||||
status = STATUS_NO_MEMORY;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
fileio->already = total;
|
|
||||||
fileio->count = length;
|
|
||||||
fileio->buffer = buffer;
|
|
||||||
|
|
||||||
SERVER_START_REQ( register_async )
|
|
||||||
{
|
|
||||||
req->type = ASYNC_TYPE_WRITE;
|
|
||||||
req->count = length;
|
|
||||||
req->async = server_async( hFile, &fileio->io, hEvent, apc, apc_user, io_status );
|
|
||||||
status = wine_server_call( req );
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, fileio );
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
else /* synchronous write, wait for the fd to become ready */
|
|
||||||
{
|
|
||||||
struct pollfd pfd;
|
|
||||||
int ret, timeout;
|
|
||||||
|
|
||||||
if (!timeout_init_done)
|
|
||||||
{
|
|
||||||
timeout_init_done = TRUE;
|
|
||||||
if ((status = get_io_timeouts( hFile, type, length, FALSE, &timeouts )))
|
|
||||||
goto err;
|
|
||||||
if (hEvent) NtResetEvent( hEvent, NULL );
|
|
||||||
}
|
|
||||||
timeout = get_next_io_timeout( &timeouts, total );
|
|
||||||
|
|
||||||
pfd.fd = unix_handle;
|
|
||||||
pfd.events = POLLOUT;
|
|
||||||
|
|
||||||
if (!timeout || !(ret = poll( &pfd, 1, timeout )))
|
|
||||||
{
|
|
||||||
/* return with what we got so far */
|
|
||||||
status = total ? STATUS_SUCCESS : STATUS_TIMEOUT;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (ret == -1 && errno != EINTR)
|
|
||||||
{
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* will now restart the write */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
send_completion = cvalue != 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (needs_close) close( unix_handle );
|
|
||||||
|
|
||||||
if (type == FD_TYPE_SERIAL && (status == STATUS_SUCCESS || status == STATUS_PENDING))
|
|
||||||
set_pending_write( hFile );
|
|
||||||
|
|
||||||
if (status == STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
io_status->u.Status = status;
|
|
||||||
io_status->Information = total;
|
|
||||||
TRACE("= SUCCESS (%u)\n", total);
|
|
||||||
if (hEvent) NtSetEvent( hEvent, NULL );
|
|
||||||
if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
|
|
||||||
(ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACE("= 0x%08x\n", status);
|
|
||||||
if (status != STATUS_PENDING && hEvent) NtResetEvent( hEvent, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
ret_status = async_write && type == FD_TYPE_FILE && status == STATUS_SUCCESS ? STATUS_PENDING : status;
|
|
||||||
if (send_completion) NTDLL_AddCompletion( hFile, cvalue, status, total, ret_status == STATUS_PENDING );
|
|
||||||
|
|
||||||
return ret_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1253,87 +425,8 @@ NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
|
||||||
PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
|
PIO_STATUS_BLOCK io_status, FILE_SEGMENT_ELEMENT *segments,
|
||||||
ULONG length, PLARGE_INTEGER offset, PULONG key )
|
ULONG length, PLARGE_INTEGER offset, PULONG key )
|
||||||
{
|
{
|
||||||
int result, unix_handle, needs_close;
|
return unix_funcs->NtWriteFileGather( file, event, apc, apc_user, io_status,
|
||||||
unsigned int options;
|
segments, length, offset, key );
|
||||||
NTSTATUS status;
|
|
||||||
ULONG pos = 0, total = 0;
|
|
||||||
enum server_fd_type type;
|
|
||||||
ULONG_PTR cvalue = apc ? 0 : (ULONG_PTR)apc_user;
|
|
||||||
BOOL send_completion = FALSE;
|
|
||||||
|
|
||||||
TRACE( "(%p,%p,%p,%p,%p,%p,0x%08x,%p,%p),partial stub!\n",
|
|
||||||
file, event, apc, apc_user, io_status, segments, length, offset, key);
|
|
||||||
|
|
||||||
if (length % page_size) return STATUS_INVALID_PARAMETER;
|
|
||||||
if (!io_status) return STATUS_ACCESS_VIOLATION;
|
|
||||||
|
|
||||||
status = unix_funcs->server_get_unix_fd( file, FILE_WRITE_DATA, &unix_handle,
|
|
||||||
&needs_close, &type, &options );
|
|
||||||
if (status) return status;
|
|
||||||
|
|
||||||
if ((type != FD_TYPE_FILE) ||
|
|
||||||
(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) ||
|
|
||||||
!(options & FILE_NO_INTERMEDIATE_BUFFERING))
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_PARAMETER;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (length)
|
|
||||||
{
|
|
||||||
if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
|
|
||||||
result = pwrite( unix_handle, (char *)segments->Buffer + pos,
|
|
||||||
page_size - pos, offset->QuadPart + total );
|
|
||||||
else
|
|
||||||
result = write( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
|
|
||||||
|
|
||||||
if (result == -1)
|
|
||||||
{
|
|
||||||
if (errno == EINTR) continue;
|
|
||||||
if (errno == EFAULT)
|
|
||||||
{
|
|
||||||
status = STATUS_INVALID_USER_BUFFER;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
status = FILE_GetNtStatus();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
status = STATUS_DISK_FULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
total += result;
|
|
||||||
length -= result;
|
|
||||||
if ((pos += result) == page_size)
|
|
||||||
{
|
|
||||||
pos = 0;
|
|
||||||
segments++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
send_completion = cvalue != 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (needs_close) close( unix_handle );
|
|
||||||
if (status == STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
io_status->u.Status = status;
|
|
||||||
io_status->Information = total;
|
|
||||||
TRACE("= SUCCESS (%u)\n", total);
|
|
||||||
if (event) NtSetEvent( event, NULL );
|
|
||||||
if (apc) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc,
|
|
||||||
(ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACE("= 0x%08x\n", status);
|
|
||||||
if (status != STATUS_PENDING && event) NtResetEvent( event, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send_completion) NTDLL_AddCompletion( file, cvalue, status, total, FALSE );
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -150,10 +150,6 @@ extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
|
||||||
SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
|
SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
|
||||||
extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN;
|
extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
/* completion */
|
|
||||||
extern NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
|
|
||||||
NTSTATUS CompletionStatus, ULONG Information, BOOL async) DECLSPEC_HIDDEN;
|
|
||||||
|
|
||||||
/* locale */
|
/* locale */
|
||||||
extern LCID user_lcid, system_lcid;
|
extern LCID user_lcid, system_lcid;
|
||||||
extern DWORD ntdll_umbstowcs( const char* src, DWORD srclen, WCHAR* dst, DWORD dstlen ) DECLSPEC_HIDDEN;
|
extern DWORD ntdll_umbstowcs( const char* src, DWORD srclen, WCHAR* dst, DWORD dstlen ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -582,24 +582,6 @@ NTSTATUS WINAPI NtQueryIoCompletion( HANDLE handle, IO_COMPLETION_INFORMATION_CL
|
||||||
return unix_funcs->NtQueryIoCompletion( handle, class, buffer, len, ret_len );
|
return unix_funcs->NtQueryIoCompletion( handle, class, buffer, len, ret_len );
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
|
|
||||||
NTSTATUS CompletionStatus, ULONG Information, BOOL async )
|
|
||||||
{
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
SERVER_START_REQ( add_fd_completion )
|
|
||||||
{
|
|
||||||
req->handle = wine_server_obj_handle( hFile );
|
|
||||||
req->cvalue = CompletionValue;
|
|
||||||
req->status = CompletionStatus;
|
|
||||||
req->information = Information;
|
|
||||||
req->async = async;
|
|
||||||
status = wine_server_call( req );
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* RtlRunOnceInitialize (NTDLL.@)
|
* RtlRunOnceInitialize (NTDLL.@)
|
||||||
*/
|
*/
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -878,6 +878,8 @@ static struct unix_funcs unix_funcs =
|
||||||
NtQueryVirtualMemory,
|
NtQueryVirtualMemory,
|
||||||
NtQueueApcThread,
|
NtQueueApcThread,
|
||||||
NtRaiseException,
|
NtRaiseException,
|
||||||
|
NtReadFile,
|
||||||
|
NtReadFileScatter,
|
||||||
NtReadVirtualMemory,
|
NtReadVirtualMemory,
|
||||||
NtReleaseKeyedEvent,
|
NtReleaseKeyedEvent,
|
||||||
NtReleaseMutant,
|
NtReleaseMutant,
|
||||||
|
@ -906,6 +908,8 @@ static struct unix_funcs unix_funcs =
|
||||||
NtWaitForKeyedEvent,
|
NtWaitForKeyedEvent,
|
||||||
NtWaitForMultipleObjects,
|
NtWaitForMultipleObjects,
|
||||||
NtWaitForSingleObject,
|
NtWaitForSingleObject,
|
||||||
|
NtWriteFile,
|
||||||
|
NtWriteFileGather,
|
||||||
NtWriteVirtualMemory,
|
NtWriteVirtualMemory,
|
||||||
NtYieldExecution,
|
NtYieldExecution,
|
||||||
DbgUiIssueRemoteBreakin,
|
DbgUiIssueRemoteBreakin,
|
||||||
|
@ -939,10 +943,7 @@ static struct unix_funcs unix_funcs =
|
||||||
virtual_create_builtin_view,
|
virtual_create_builtin_view,
|
||||||
virtual_alloc_thread_stack,
|
virtual_alloc_thread_stack,
|
||||||
virtual_locked_server_call,
|
virtual_locked_server_call,
|
||||||
virtual_locked_read,
|
|
||||||
virtual_locked_pread,
|
|
||||||
virtual_locked_recvmsg,
|
virtual_locked_recvmsg,
|
||||||
virtual_check_buffer_for_read,
|
|
||||||
virtual_check_buffer_for_write,
|
virtual_check_buffer_for_write,
|
||||||
virtual_release_address_space,
|
virtual_release_address_space,
|
||||||
virtual_set_large_address_space,
|
virtual_set_large_address_space,
|
||||||
|
|
|
@ -54,6 +54,8 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
|
||||||
return (struct ntdll_thread_data *)&NtCurrentTeb()->GdiTebBatch;
|
return (struct ntdll_thread_data *)&NtCurrentTeb()->GdiTebBatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const UINT_PTR page_size = 0x1000;
|
||||||
|
|
||||||
NTSTATUS WINAPI KiUserExceptionDispatcher(EXCEPTION_RECORD*,CONTEXT*);
|
NTSTATUS WINAPI KiUserExceptionDispatcher(EXCEPTION_RECORD*,CONTEXT*);
|
||||||
void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR);
|
void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR);
|
||||||
|
|
||||||
|
@ -89,10 +91,7 @@ extern void CDECL virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECL
|
||||||
extern NTSTATUS CDECL virtual_create_builtin_view( void *module ) DECLSPEC_HIDDEN;
|
extern NTSTATUS CDECL virtual_create_builtin_view( void *module ) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS CDECL virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN;
|
extern NTSTATUS CDECL virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN;
|
||||||
extern unsigned int CDECL virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
|
extern unsigned int CDECL virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
|
||||||
extern ssize_t CDECL virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN;
|
|
||||||
extern ssize_t CDECL virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) DECLSPEC_HIDDEN;
|
|
||||||
extern ssize_t CDECL virtual_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) DECLSPEC_HIDDEN;
|
extern ssize_t CDECL virtual_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) DECLSPEC_HIDDEN;
|
||||||
extern BOOL CDECL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
|
||||||
extern BOOL CDECL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
extern BOOL CDECL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN;
|
extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL virtual_set_large_address_space(void) DECLSPEC_HIDDEN;
|
extern void CDECL virtual_set_large_address_space(void) DECLSPEC_HIDDEN;
|
||||||
|
@ -174,8 +173,11 @@ extern NTSTATUS virtual_alloc_teb( TEB **ret_teb ) DECLSPEC_HIDDEN;
|
||||||
extern void virtual_free_teb( TEB *teb ) DECLSPEC_HIDDEN;
|
extern void virtual_free_teb( TEB *teb ) DECLSPEC_HIDDEN;
|
||||||
extern void virtual_map_user_shared_data(void) DECLSPEC_HIDDEN;
|
extern void virtual_map_user_shared_data(void) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN;
|
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN;
|
||||||
|
extern ssize_t virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN;
|
||||||
|
extern ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) DECLSPEC_HIDDEN;
|
||||||
extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
extern int virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
|
extern int virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
|
||||||
|
extern BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
extern NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
extern void virtual_set_force_exec( BOOL enable ) DECLSPEC_HIDDEN;
|
extern void virtual_set_force_exec( BOOL enable ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -134,7 +134,6 @@ static RTL_CRITICAL_SECTION csVirtual = { &critsect_debug, -1, 0, 0, 0, 0 };
|
||||||
|
|
||||||
static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
|
static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
|
||||||
static const UINT page_shift = 12;
|
static const UINT page_shift = 12;
|
||||||
static const UINT_PTR page_size = 0x1000;
|
|
||||||
static const UINT_PTR page_mask = 0xfff;
|
static const UINT_PTR page_mask = 0xfff;
|
||||||
static const UINT_PTR granularity_mask = 0xffff;
|
static const UINT_PTR granularity_mask = 0xffff;
|
||||||
|
|
||||||
|
@ -2866,7 +2865,7 @@ unsigned int CDECL virtual_locked_server_call( void *req_ptr )
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* virtual_locked_read
|
* virtual_locked_read
|
||||||
*/
|
*/
|
||||||
ssize_t CDECL virtual_locked_read( int fd, void *addr, size_t size )
|
ssize_t virtual_locked_read( int fd, void *addr, size_t size )
|
||||||
{
|
{
|
||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
BOOL has_write_watch = FALSE;
|
BOOL has_write_watch = FALSE;
|
||||||
|
@ -2891,7 +2890,7 @@ ssize_t CDECL virtual_locked_read( int fd, void *addr, size_t size )
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* virtual_locked_pread
|
* virtual_locked_pread
|
||||||
*/
|
*/
|
||||||
ssize_t CDECL virtual_locked_pread( int fd, void *addr, size_t size, off_t offset )
|
ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset )
|
||||||
{
|
{
|
||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
BOOL has_write_watch = FALSE;
|
BOOL has_write_watch = FALSE;
|
||||||
|
@ -3007,7 +3006,7 @@ int virtual_handle_stack_fault( void *addr )
|
||||||
*
|
*
|
||||||
* Check if a memory buffer can be read, triggering page faults if needed for DIB section access.
|
* Check if a memory buffer can be read, triggering page faults if needed for DIB section access.
|
||||||
*/
|
*/
|
||||||
BOOL CDECL virtual_check_buffer_for_read( const void *ptr, SIZE_T size )
|
BOOL virtual_check_buffer_for_read( const void *ptr, SIZE_T size )
|
||||||
{
|
{
|
||||||
if (!size) return TRUE;
|
if (!size) return TRUE;
|
||||||
if (!ptr) return FALSE;
|
if (!ptr) return FALSE;
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct ldt_copy;
|
||||||
struct msghdr;
|
struct msghdr;
|
||||||
|
|
||||||
/* increment this when you change the function table */
|
/* increment this when you change the function table */
|
||||||
#define NTDLL_UNIXLIB_VERSION 48
|
#define NTDLL_UNIXLIB_VERSION 49
|
||||||
|
|
||||||
struct unix_funcs
|
struct unix_funcs
|
||||||
{
|
{
|
||||||
|
@ -159,6 +159,13 @@ struct unix_funcs
|
||||||
NTSTATUS (WINAPI *NtQueueApcThread)( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
|
NTSTATUS (WINAPI *NtQueueApcThread)( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
|
||||||
ULONG_PTR arg2, ULONG_PTR arg3 );
|
ULONG_PTR arg2, ULONG_PTR arg3 );
|
||||||
NTSTATUS (WINAPI *NtRaiseException)( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance );
|
NTSTATUS (WINAPI *NtRaiseException)( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance );
|
||||||
|
NTSTATUS (WINAPI *NtReadFile)( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
|
||||||
|
IO_STATUS_BLOCK *io, void *buffer, ULONG length,
|
||||||
|
LARGE_INTEGER *offset, ULONG *key );
|
||||||
|
NTSTATUS (WINAPI *NtReadFileScatter)( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc,
|
||||||
|
void *apc_user, IO_STATUS_BLOCK *io,
|
||||||
|
FILE_SEGMENT_ELEMENT *segments, ULONG length,
|
||||||
|
LARGE_INTEGER *offset, ULONG *key );
|
||||||
NTSTATUS (WINAPI *NtReadVirtualMemory)( HANDLE process, const void *addr, void *buffer,
|
NTSTATUS (WINAPI *NtReadVirtualMemory)( HANDLE process, const void *addr, void *buffer,
|
||||||
SIZE_T size, SIZE_T *bytes_read );
|
SIZE_T size, SIZE_T *bytes_read );
|
||||||
NTSTATUS (WINAPI *NtReleaseKeyedEvent)( HANDLE handle, const void *key,
|
NTSTATUS (WINAPI *NtReleaseKeyedEvent)( HANDLE handle, const void *key,
|
||||||
|
@ -204,6 +211,13 @@ struct unix_funcs
|
||||||
const LARGE_INTEGER *timeout );
|
const LARGE_INTEGER *timeout );
|
||||||
NTSTATUS (WINAPI *NtWaitForSingleObject)( HANDLE handle, BOOLEAN alertable,
|
NTSTATUS (WINAPI *NtWaitForSingleObject)( HANDLE handle, BOOLEAN alertable,
|
||||||
const LARGE_INTEGER *timeout );
|
const LARGE_INTEGER *timeout );
|
||||||
|
NTSTATUS (WINAPI *NtWriteFile)( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
|
||||||
|
IO_STATUS_BLOCK *io, const void *buffer, ULONG length,
|
||||||
|
LARGE_INTEGER *offset, ULONG *key );
|
||||||
|
NTSTATUS (WINAPI *NtWriteFileGather)( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc,
|
||||||
|
void *apc_user, IO_STATUS_BLOCK *io,
|
||||||
|
FILE_SEGMENT_ELEMENT *segments, ULONG length,
|
||||||
|
LARGE_INTEGER *offset, ULONG *key );
|
||||||
NTSTATUS (WINAPI *NtWriteVirtualMemory)( HANDLE process, void *addr, const void *buffer,
|
NTSTATUS (WINAPI *NtWriteVirtualMemory)( HANDLE process, void *addr, const void *buffer,
|
||||||
SIZE_T size, SIZE_T *bytes_written );
|
SIZE_T size, SIZE_T *bytes_written );
|
||||||
NTSTATUS (WINAPI *NtYieldExecution)(void);
|
NTSTATUS (WINAPI *NtYieldExecution)(void);
|
||||||
|
@ -253,10 +267,7 @@ struct unix_funcs
|
||||||
NTSTATUS (CDECL *virtual_create_builtin_view)( void *module );
|
NTSTATUS (CDECL *virtual_create_builtin_view)( void *module );
|
||||||
NTSTATUS (CDECL *virtual_alloc_thread_stack)( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size );
|
NTSTATUS (CDECL *virtual_alloc_thread_stack)( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size );
|
||||||
unsigned int (CDECL *virtual_locked_server_call)( void *req_ptr );
|
unsigned int (CDECL *virtual_locked_server_call)( void *req_ptr );
|
||||||
ssize_t (CDECL *virtual_locked_read)( int fd, void *addr, size_t size );
|
|
||||||
ssize_t (CDECL *virtual_locked_pread)( int fd, void *addr, size_t size, off_t offset );
|
|
||||||
ssize_t (CDECL *virtual_locked_recvmsg)( int fd, struct msghdr *hdr, int flags );
|
ssize_t (CDECL *virtual_locked_recvmsg)( int fd, struct msghdr *hdr, int flags );
|
||||||
BOOL (CDECL *virtual_check_buffer_for_read)( const void *ptr, SIZE_T size );
|
|
||||||
BOOL (CDECL *virtual_check_buffer_for_write)( void *ptr, SIZE_T size );
|
BOOL (CDECL *virtual_check_buffer_for_write)( void *ptr, SIZE_T size );
|
||||||
void (CDECL *virtual_release_address_space)(void);
|
void (CDECL *virtual_release_address_space)(void);
|
||||||
void (CDECL *virtual_set_large_address_space)(void);
|
void (CDECL *virtual_set_large_address_space)(void);
|
||||||
|
|
Loading…
Reference in New Issue