[PATCH v4 3/3] ntdll: Don't require full-page reads in NtReadFileScatter

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[PATCH v4 3/3] ntdll: Don't require full-page reads in NtReadFileScatter

Andrew Eikum-2
Signed-off-by: Andrew Eikum <[hidden email]>
---
 dlls/kernel32/tests/file.c | 30 +++++++++++++++++++++++++++++-
 dlls/ntdll/file.c          |  5 ++---
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 94feee6372..410c3f0591 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -4353,7 +4353,7 @@ static void test_WriteFileGather(void)
     FILE_SEGMENT_ELEMENT fse[2];
     OVERLAPPED ovl, *povl = NULL;
     SYSTEM_INFO si;
-    LPVOID wbuf = NULL, rbuf1, rbuf2;
+    char *wbuf = NULL, *rbuf1, *rbuf2;
     BOOL br;
 
     evt = CreateEventW( NULL, TRUE, FALSE, NULL );
@@ -4492,6 +4492,34 @@ static void test_WriteFileGather(void)
     ok( memcmp( rbuf2, rbuf1, si.dwPageSize ) == 0,
             "data should not have been read into buffer\n" );
 
+    ResetEvent( evt );
+
+    /* partial page read */
+    memset( &ovl, 0, sizeof(ovl) );
+    ovl.hEvent = evt;
+    memset( fse, 0, sizeof(fse) );
+    fse[0].Buffer = rbuf1;
+    memset( rbuf1, 0, si.dwPageSize );
+    SetLastError( 0xdeadbeef );
+    br = ReadFileScatter( hfile, fse, si.dwPageSize / 2, NULL, &ovl );
+    ok( br == FALSE, "ReadFileScatter should be asynchronous\n" );
+    ok( GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed err %u\n", GetLastError() );
+
+    ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 );
+    ok( ret, "GetQueuedCompletionStatus failed err %u\n", GetLastError() );
+    ok( povl == &ovl, "wrong ovl %p\n", povl );
+
+    tx = 0;
+    br = GetOverlappedResult( hfile, &ovl, &tx, TRUE );
+    ok( br == TRUE, "GetOverlappedResult failed: %u\n", GetLastError() );
+    ok( tx == si.dwPageSize / 2, "got unexpected bytes transferred: %u\n", tx );
+
+    ok( memcmp( rbuf1, wbuf, si.dwPageSize / 2 ) == 0,
+            "invalid data was read into buffer\n" );
+    memset( rbuf2, 0, si.dwPageSize );
+    ok( memcmp( rbuf1 + si.dwPageSize / 2, rbuf2, si.dwPageSize - si.dwPageSize / 2 ) == 0,
+            "invalid data was read into buffer\n" );
+
     CloseHandle( hfile );
     CloseHandle( hiocp1 );
     CloseHandle( hiocp2 );
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 3d4a94923b..570e46c0a7 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1041,7 +1041,6 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
     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 = server_get_unix_fd( file, FILE_READ_DATA, &unix_handle,
@@ -1060,9 +1059,9 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap
     {
         if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
             result = pread( unix_handle, (char *)segments->Buffer + pos,
-                            page_size - pos, offset->QuadPart + total );
+                            min( length - pos, page_size - pos ), offset->QuadPart + total );
         else
-            result = read( unix_handle, (char *)segments->Buffer + pos, page_size - pos );
+            result = read( unix_handle, (char *)segments->Buffer + pos, min( length - pos, page_size - pos ) );
 
         if (result == -1)
         {
--
2.15.1