Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
888d66a2
Commit
888d66a2
authored
Jun 16, 2020
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Move the file read/write functions to the Unix library.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
e9e5c950
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1104 additions
and
949 deletions
+1104
-949
file.c
dlls/ntdll/file.c
+6
-913
ntdll_misc.h
dlls/ntdll/ntdll_misc.h
+0
-4
sync.c
dlls/ntdll/sync.c
+0
-18
file.c
dlls/ntdll/unix/file.c
+1071
-0
loader.c
dlls/ntdll/unix/loader.c
+4
-3
unix_private.h
dlls/ntdll/unix/unix_private.h
+5
-3
virtual.c
dlls/ntdll/unix/virtual.c
+3
-4
unixlib.h
dlls/ntdll/unixlib.h
+15
-4
No files found.
dlls/ntdll/file.c
View file @
888d66a2
...
...
@@ -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.@]
...
...
@@ -657,196 +367,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
PIO_STATUS_BLOCK
io_status
,
void
*
buffer
,
ULONG
length
,
PLARGE_INTEGER
offset
,
PULONG
key
)
{
int
result
,
unix_handle
,
needs_close
;
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
;
return
unix_funcs
->
NtReadFile
(
hFile
,
hEvent
,
apc
,
apc_user
,
io_status
,
buffer
,
length
,
offset
,
key
);
}
...
...
@@ -858,144 +379,11 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
PIO_STATUS_BLOCK
io_status
,
FILE_SEGMENT_ELEMENT
*
segments
,
ULONG
length
,
PLARGE_INTEGER
offset
,
PULONG
key
)
{
int
result
,
unix_handle
,
needs_close
;
unsigned
int
options
;
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
;
return
unix_funcs
->
NtReadFileScatter
(
file
,
event
,
apc
,
apc_user
,
io_status
,
segments
,
length
,
offset
,
key
);
}
/***********************************************************************
* 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.@]
...
...
@@ -1025,223 +413,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
const
void
*
buffer
,
ULONG
length
,
PLARGE_INTEGER
offset
,
PULONG
key
)
{
int
result
,
unix_handle
,
needs_close
;
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
;
return
unix_funcs
->
NtWriteFile
(
hFile
,
hEvent
,
apc
,
apc_user
,
io_status
,
buffer
,
length
,
offset
,
key
);
}
...
...
@@ -1253,87 +425,8 @@ NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
PIO_STATUS_BLOCK
io_status
,
FILE_SEGMENT_ELEMENT
*
segments
,
ULONG
length
,
PLARGE_INTEGER
offset
,
PULONG
key
)
{
int
result
,
unix_handle
,
needs_close
;
unsigned
int
options
;
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
;
return
unix_funcs
->
NtWriteFileGather
(
file
,
event
,
apc
,
apc_user
,
io_status
,
segments
,
length
,
offset
,
key
);
}
...
...
dlls/ntdll/ntdll_misc.h
View file @
888d66a2
...
...
@@ -150,10 +150,6 @@ extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
SECTION_IMAGE_INFORMATION
*
info
)
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 */
extern
LCID
user_lcid
,
system_lcid
;
extern
DWORD
ntdll_umbstowcs
(
const
char
*
src
,
DWORD
srclen
,
WCHAR
*
dst
,
DWORD
dstlen
)
DECLSPEC_HIDDEN
;
...
...
dlls/ntdll/sync.c
View file @
888d66a2
...
...
@@ -582,24 +582,6 @@ NTSTATUS WINAPI NtQueryIoCompletion( HANDLE handle, IO_COMPLETION_INFORMATION_CL
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.@)
*/
...
...
dlls/ntdll/unix/file.c
View file @
888d66a2
...
...
@@ -40,6 +40,9 @@
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
...
...
@@ -112,6 +115,7 @@
#include "winioctl.h"
#include "winternl.h"
#include "ddk/ntddk.h"
#include "ddk/ntddser.h"
#include "ddk/wdm.h"
#define WINE_MOUNTMGR_EXTENSIONS
#include "ddk/mountmgr.h"
...
...
@@ -125,6 +129,9 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
#define MAX_DOS_DRIVES 26
#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
/* just in case... */
#undef VFAT_IOCTL_READDIR_BOTH
#undef EXT2_IOC_GETFLAGS
...
...
@@ -4282,3 +4289,1067 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
io
->
Information
=
0
;
return
io
->
u
.
Status
;
}
/***********************************************************************
* Asynchronous file I/O *
*/
typedef
NTSTATUS
async_callback_t
(
void
*
user
,
IO_STATUS_BLOCK
*
io
,
NTSTATUS
status
);
struct
async_fileio
{
async_callback_t
*
callback
;
/* must be the first field */
struct
async_fileio
*
next
;
HANDLE
handle
;
};
struct
async_fileio_read
{
struct
async_fileio
io
;
char
*
buffer
;
unsigned
int
already
;
unsigned
int
count
;
BOOL
avail_mode
;
};
struct
async_fileio_write
{
struct
async_fileio
io
;
const
char
*
buffer
;
unsigned
int
already
;
unsigned
int
count
;
};
struct
async_irp
{
struct
async_fileio
io
;
void
*
buffer
;
/* buffer for output */
ULONG
size
;
/* size of buffer */
};
static
struct
async_fileio
*
fileio_freelist
;
static
void
release_fileio
(
struct
async_fileio
*
io
)
{
for
(;;)
{
struct
async_fileio
*
next
=
fileio_freelist
;
io
->
next
=
next
;
if
(
InterlockedCompareExchangePointer
(
(
void
**
)
&
fileio_freelist
,
io
,
next
)
==
next
)
return
;
}
}
static
struct
async_fileio
*
alloc_fileio
(
DWORD
size
,
async_callback_t
callback
,
HANDLE
handle
)
{
/* first free remaining previous fileinfos */
struct
async_fileio
*
io
=
InterlockedExchangePointer
(
(
void
**
)
&
fileio_freelist
,
NULL
);
while
(
io
)
{
struct
async_fileio
*
next
=
io
->
next
;
RtlFreeHeap
(
GetProcessHeap
(),
0
,
io
);
io
=
next
;
}
if
((
io
=
RtlAllocateHeap
(
GetProcessHeap
(),
0
,
size
)))
{
io
->
callback
=
callback
;
io
->
handle
=
handle
;
}
return
io
;
}
static
async_data_t
server_async
(
HANDLE
handle
,
struct
async_fileio
*
user
,
HANDLE
event
,
PIO_APC_ROUTINE
apc
,
void
*
apc_context
,
IO_STATUS_BLOCK
*
io
)
{
async_data_t
async
;
async
.
handle
=
wine_server_obj_handle
(
handle
);
async
.
user
=
wine_server_client_ptr
(
user
);
async
.
iosb
=
wine_server_client_ptr
(
io
);
async
.
event
=
wine_server_obj_handle
(
event
);
async
.
apc
=
wine_server_client_ptr
(
apc
);
async
.
apc_context
=
wine_server_client_ptr
(
apc_context
);
return
async
;
}
static
NTSTATUS
wait_async
(
HANDLE
handle
,
BOOL
alertable
,
IO_STATUS_BLOCK
*
io
)
{
if
(
NtWaitForSingleObject
(
handle
,
alertable
,
NULL
))
return
STATUS_PENDING
;
return
io
->
u
.
Status
;
}
/* callback for irp async I/O completion */
static
NTSTATUS
irp_completion
(
void
*
user
,
IO_STATUS_BLOCK
*
io
,
NTSTATUS
status
)
{
struct
async_irp
*
async
=
user
;
ULONG
information
=
0
;
if
(
status
==
STATUS_ALERTED
)
{
SERVER_START_REQ
(
get_async_result
)
{
req
->
user_arg
=
wine_server_client_ptr
(
async
);
wine_server_set_reply
(
req
,
async
->
buffer
,
async
->
size
);
status
=
virtual_locked_server_call
(
req
);
information
=
reply
->
size
;
}
SERVER_END_REQ
;
}
if
(
status
!=
STATUS_PENDING
)
{
io
->
u
.
Status
=
status
;
io
->
Information
=
information
;
release_fileio
(
&
async
->
io
);
}
return
status
;
}
static
NTSTATUS
async_read_proc
(
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
=
server_get_unix_fd
(
fileio
->
io
.
handle
,
FILE_READ_DATA
,
&
fd
,
&
needs_close
,
NULL
,
NULL
)))
break
;
result
=
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
=
errno_to_status
(
errno
);
}
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
;
}
static
NTSTATUS
async_write_proc
(
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
=
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
=
errno_to_status
(
errno
);
}
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
;
}
/* 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
=
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
),
async_read_proc
,
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
;
}
static
void
add_completion
(
HANDLE
handle
,
ULONG_PTR
value
,
NTSTATUS
status
,
ULONG
info
,
BOOL
async
)
{
SERVER_START_REQ
(
add_fd_completion
)
{
req
->
handle
=
wine_server_obj_handle
(
handle
);
req
->
cvalue
=
value
;
req
->
status
=
status
;
req
->
information
=
info
;
req
->
async
=
async
;
wine_server_call
(
req
);
}
SERVER_END_REQ
;
}
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
;
}
/******************************************************************************
* NtReadFile (NTDLL.@)
*/
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
)
{
int
result
,
unix_handle
,
needs_close
;
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
"
,
handle
,
event
,
apc
,
apc_user
,
io
,
buffer
,
length
,
offset
,
key
);
if
(
!
io
)
return
STATUS_ACCESS_VIOLATION
;
status
=
server_get_unix_fd
(
handle
,
FILE_READ_DATA
,
&
unix_handle
,
&
needs_close
,
&
type
,
&
options
);
if
(
status
&&
status
!=
STATUS_BAD_DEVICE_TYPE
)
return
status
;
if
(
!
virtual_check_buffer_for_write
(
buffer
,
length
))
return
STATUS_ACCESS_VIOLATION
;
if
(
status
==
STATUS_BAD_DEVICE_TYPE
)
return
server_read_file
(
handle
,
event
,
apc
,
apc_user
,
io
,
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
=
virtual_locked_pread
(
unix_handle
,
buffer
,
length
,
offset
->
QuadPart
))
==
-
1
)
{
if
(
errno
!=
EINTR
)
{
status
=
errno_to_status
(
errno
);
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
(
handle
,
type
,
length
,
TRUE
,
&
timeouts
)))
goto
err
;
if
(
timeouts
.
interval
)
{
status
=
register_async_file_read
(
handle
,
event
,
apc
,
apc_user
,
io
,
buffer
,
total
,
length
,
FALSE
);
goto
err
;
}
}
for
(;;)
{
if
((
result
=
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
=
errno_to_status
(
errno
);
goto
err
;
}
if
(
async_read
)
{
BOOL
avail_mode
;
if
((
status
=
get_io_avail_mode
(
handle
,
type
,
&
avail_mode
)))
goto
err
;
if
(
total
&&
avail_mode
)
{
status
=
STATUS_SUCCESS
;
goto
done
;
}
status
=
register_async_file_read
(
handle
,
event
,
apc
,
apc_user
,
io
,
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
(
handle
,
type
,
length
,
TRUE
,
&
timeouts
)))
goto
err
;
if
(
event
)
NtResetEvent
(
event
,
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
=
errno_to_status
(
errno
);
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
->
u
.
Status
=
status
;
io
->
Information
=
total
;
TRACE
(
"= SUCCESS (%u)
\n
"
,
total
);
if
(
event
)
NtSetEvent
(
event
,
NULL
);
if
(
apc
&&
(
!
status
||
async_read
))
NtQueueApcThread
(
GetCurrentThread
(),
(
PNTAPCFUNC
)
apc
,
(
ULONG_PTR
)
apc_user
,
(
ULONG_PTR
)
io
,
0
);
}
else
{
TRACE
(
"= 0x%08x
\n
"
,
status
);
if
(
status
!=
STATUS_PENDING
&&
event
)
NtResetEvent
(
event
,
NULL
);
}
ret_status
=
async_read
&&
type
==
FD_TYPE_FILE
&&
(
status
==
STATUS_SUCCESS
||
status
==
STATUS_END_OF_FILE
)
?
STATUS_PENDING
:
status
;
if
(
send_completion
)
add_completion
(
handle
,
cvalue
,
status
,
total
,
ret_status
==
STATUS_PENDING
);
return
ret_status
;
}
/******************************************************************************
* NtReadFileScatter (NTDLL.@)
*/
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
)
{
int
result
,
unix_handle
,
needs_close
;
unsigned
int
options
;
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
,
segments
,
length
,
offset
,
key
);
if
(
!
io
)
return
STATUS_ACCESS_VIOLATION
;
status
=
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
=
errno_to_status
(
errno
);
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
->
u
.
Status
=
status
;
io
->
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
,
0
);
if
(
send_completion
)
add_completion
(
file
,
cvalue
,
status
,
total
,
TRUE
);
return
STATUS_PENDING
;
error:
if
(
needs_close
)
close
(
unix_handle
);
if
(
event
)
NtResetEvent
(
event
,
NULL
);
TRACE
(
"= 0x%08x
\n
"
,
status
);
return
status
;
}
/******************************************************************************
* NtWriteFile (NTDLL.@)
*/
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
)
{
int
result
,
unix_handle
,
needs_close
;
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
"
,
handle
,
event
,
apc
,
apc_user
,
io
,
buffer
,
length
,
offset
,
key
);
if
(
!
io
)
return
STATUS_ACCESS_VIOLATION
;
status
=
server_get_unix_fd
(
handle
,
FILE_WRITE_DATA
,
&
unix_handle
,
&
needs_close
,
&
type
,
&
options
);
if
(
status
==
STATUS_ACCESS_DENIED
)
{
status
=
server_get_unix_fd
(
handle
,
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
(
!
virtual_check_buffer_for_read
(
buffer
,
length
))
{
status
=
STATUS_INVALID_USER_BUFFER
;
goto
done
;
}
if
(
status
==
STATUS_BAD_DEVICE_TYPE
)
return
server_write_file
(
handle
,
event
,
apc
,
apc_user
,
io
,
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
=
errno_to_status
(
errno
);
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
=
errno_to_status
(
errno
);
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
=
errno_to_status
(
errno
);
}
goto
err
;
}
if
(
async_write
)
{
struct
async_fileio_write
*
fileio
;
fileio
=
(
struct
async_fileio_write
*
)
alloc_fileio
(
sizeof
(
*
fileio
),
async_write_proc
,
handle
);
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
(
handle
,
&
fileio
->
io
,
event
,
apc
,
apc_user
,
io
);
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
(
handle
,
type
,
length
,
FALSE
,
&
timeouts
)))
goto
err
;
if
(
event
)
NtResetEvent
(
event
,
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
=
errno_to_status
(
errno
);
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
(
handle
);
if
(
status
==
STATUS_SUCCESS
)
{
io
->
u
.
Status
=
status
;
io
->
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
,
0
);
}
else
{
TRACE
(
"= 0x%08x
\n
"
,
status
);
if
(
status
!=
STATUS_PENDING
&&
event
)
NtResetEvent
(
event
,
NULL
);
}
ret_status
=
async_write
&&
type
==
FD_TYPE_FILE
&&
status
==
STATUS_SUCCESS
?
STATUS_PENDING
:
status
;
if
(
send_completion
)
add_completion
(
handle
,
cvalue
,
status
,
total
,
ret_status
==
STATUS_PENDING
);
return
ret_status
;
}
/******************************************************************************
* NtWriteFileGather (NTDLL.@)
*/
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
)
{
int
result
,
unix_handle
,
needs_close
;
unsigned
int
options
;
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
,
segments
,
length
,
offset
,
key
);
if
(
length
%
page_size
)
return
STATUS_INVALID_PARAMETER
;
if
(
!
io
)
return
STATUS_ACCESS_VIOLATION
;
status
=
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
done
;
}
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
done
;
}
status
=
errno_to_status
(
errno
);
break
;
}
if
(
!
result
)
{
status
=
STATUS_DISK_FULL
;
break
;
}
total
+=
result
;
length
-=
result
;
if
((
pos
+=
result
)
==
page_size
)
{
pos
=
0
;
segments
++
;
}
}
send_completion
=
cvalue
!=
0
;
done:
if
(
needs_close
)
close
(
unix_handle
);
if
(
status
==
STATUS_SUCCESS
)
{
io
->
u
.
Status
=
status
;
io
->
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
,
0
);
}
else
{
TRACE
(
"= 0x%08x
\n
"
,
status
);
if
(
status
!=
STATUS_PENDING
&&
event
)
NtResetEvent
(
event
,
NULL
);
}
if
(
send_completion
)
add_completion
(
file
,
cvalue
,
status
,
total
,
FALSE
);
return
status
;
}
dlls/ntdll/unix/loader.c
View file @
888d66a2
...
...
@@ -878,6 +878,8 @@ static struct unix_funcs unix_funcs =
NtQueryVirtualMemory
,
NtQueueApcThread
,
NtRaiseException
,
NtReadFile
,
NtReadFileScatter
,
NtReadVirtualMemory
,
NtReleaseKeyedEvent
,
NtReleaseMutant
,
...
...
@@ -906,6 +908,8 @@ static struct unix_funcs unix_funcs =
NtWaitForKeyedEvent
,
NtWaitForMultipleObjects
,
NtWaitForSingleObject
,
NtWriteFile
,
NtWriteFileGather
,
NtWriteVirtualMemory
,
NtYieldExecution
,
DbgUiIssueRemoteBreakin
,
...
...
@@ -939,10 +943,7 @@ static struct unix_funcs unix_funcs =
virtual_create_builtin_view
,
virtual_alloc_thread_stack
,
virtual_locked_server_call
,
virtual_locked_read
,
virtual_locked_pread
,
virtual_locked_recvmsg
,
virtual_check_buffer_for_read
,
virtual_check_buffer_for_write
,
virtual_release_address_space
,
virtual_set_large_address_space
,
...
...
dlls/ntdll/unix/unix_private.h
View file @
888d66a2
...
...
@@ -54,6 +54,8 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
return
(
struct
ntdll_thread_data
*
)
&
NtCurrentTeb
()
->
GdiTebBatch
;
}
static
const
UINT_PTR
page_size
=
0x1000
;
NTSTATUS
WINAPI
KiUserExceptionDispatcher
(
EXCEPTION_RECORD
*
,
CONTEXT
*
);
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_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
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
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
void
CDECL
virtual_release_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_map_user_shared_data
(
void
)
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
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
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
;
...
...
dlls/ntdll/unix/virtual.c
View file @
888d66a2
...
...
@@ -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
UINT
page_shift
=
12
;
static
const
UINT_PTR
page_size
=
0x1000
;
static
const
UINT_PTR
page_mask
=
0xfff
;
static
const
UINT_PTR
granularity_mask
=
0xffff
;
...
...
@@ -2866,7 +2865,7 @@ unsigned int CDECL virtual_locked_server_call( void *req_ptr )
/***********************************************************************
* 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
;
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
*/
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
;
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.
*/
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
(
!
ptr
)
return
FALSE
;
...
...
dlls/ntdll/unixlib.h
View file @
888d66a2
...
...
@@ -28,7 +28,7 @@ struct ldt_copy;
struct
msghdr
;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 4
8
#define NTDLL_UNIXLIB_VERSION 4
9
struct
unix_funcs
{
...
...
@@ -159,6 +159,13 @@ struct unix_funcs
NTSTATUS
(
WINAPI
*
NtQueueApcThread
)(
HANDLE
handle
,
PNTAPCFUNC
func
,
ULONG_PTR
arg1
,
ULONG_PTR
arg2
,
ULONG_PTR
arg3
);
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
,
SIZE_T
size
,
SIZE_T
*
bytes_read
);
NTSTATUS
(
WINAPI
*
NtReleaseKeyedEvent
)(
HANDLE
handle
,
const
void
*
key
,
...
...
@@ -204,6 +211,13 @@ struct unix_funcs
const
LARGE_INTEGER
*
timeout
);
NTSTATUS
(
WINAPI
*
NtWaitForSingleObject
)(
HANDLE
handle
,
BOOLEAN
alertable
,
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
,
SIZE_T
size
,
SIZE_T
*
bytes_written
);
NTSTATUS
(
WINAPI
*
NtYieldExecution
)(
void
);
...
...
@@ -253,10 +267,7 @@ struct unix_funcs
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
);
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
);
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
);
void
(
CDECL
*
virtual_release_address_space
)(
void
);
void
(
CDECL
*
virtual_set_large_address_space
)(
void
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment