mirror of
https://github.com/decompals/wibo.git
synced 2025-12-12 14:46:09 +00:00
493 lines
17 KiB
C
493 lines
17 KiB
C
#include "test_assert.h"
|
|
#include <windows.h>
|
|
|
|
#ifndef STATUS_PENDING
|
|
#define STATUS_PENDING ((DWORD)0x00000103)
|
|
#endif
|
|
|
|
static char g_tempFilename[MAX_PATH];
|
|
|
|
struct GetOverlappedWaitArgs {
|
|
HANDLE handle;
|
|
OVERLAPPED *ov;
|
|
DWORD bytesTransferred;
|
|
BOOL result;
|
|
DWORD error;
|
|
};
|
|
|
|
static DWORD WINAPI getoverlapped_wait_thread(LPVOID param) {
|
|
struct GetOverlappedWaitArgs *args = (struct GetOverlappedWaitArgs *)param;
|
|
args->bytesTransferred = 0xFFFFFFFFu;
|
|
SetLastError(0xDEADBEEFu);
|
|
args->result = GetOverlappedResult(args->handle, args->ov, &args->bytesTransferred, TRUE);
|
|
args->error = args->result ? ERROR_SUCCESS : GetLastError();
|
|
return 0;
|
|
}
|
|
|
|
struct SyncReaderArgs {
|
|
HANDLE pipe;
|
|
OVERLAPPED *ov;
|
|
HANDLE startedEvent;
|
|
DWORD expectedBytes;
|
|
DWORD bytesRead;
|
|
BOOL readSucceeded;
|
|
};
|
|
|
|
static DWORD WINAPI sync_reader_thread(LPVOID param) {
|
|
struct SyncReaderArgs *args = (struct SyncReaderArgs *)param;
|
|
char buffer[32] = {0};
|
|
args->ov->Internal = STATUS_PENDING;
|
|
args->ov->InternalHigh = 0;
|
|
TEST_CHECK(SetEvent(args->startedEvent));
|
|
args->bytesRead = 0;
|
|
args->readSucceeded = ReadFile(args->pipe, buffer, args->expectedBytes, &args->bytesRead, args->ov);
|
|
return args->readSucceeded ? 0 : GetLastError();
|
|
}
|
|
|
|
struct SyncWriterArgs {
|
|
const char *pipeName;
|
|
HANDLE serverReadyEvent;
|
|
};
|
|
|
|
static DWORD WINAPI sync_writer_thread(LPVOID param) {
|
|
struct SyncWriterArgs *args = (struct SyncWriterArgs *)param;
|
|
TEST_CHECK(WaitForSingleObject(args->serverReadyEvent, 1000) == WAIT_OBJECT_0);
|
|
HANDLE client = CreateFileA(args->pipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
TEST_CHECK_MSG(client != INVALID_HANDLE_VALUE, "CreateFileA(client) failed: %lu", GetLastError());
|
|
Sleep(200);
|
|
static const char msg[] = "READY";
|
|
DWORD written = 0;
|
|
TEST_CHECK(WriteFile(client, msg, (DWORD)(sizeof(msg) - 1), &written, NULL));
|
|
TEST_CHECK_EQ(sizeof(msg) - 1, written);
|
|
CloseHandle(client);
|
|
return 0;
|
|
}
|
|
|
|
struct ManualEventWriterArgs {
|
|
const char *pipeName;
|
|
HANDLE serverReadyEvent;
|
|
HANDLE proceedEvent;
|
|
};
|
|
|
|
static DWORD WINAPI manual_event_writer_thread(LPVOID param) {
|
|
struct ManualEventWriterArgs *args = (struct ManualEventWriterArgs *)param;
|
|
TEST_CHECK(WaitForSingleObject(args->serverReadyEvent, 1000) == WAIT_OBJECT_0);
|
|
HANDLE client = CreateFileA(args->pipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
TEST_CHECK_MSG(client != INVALID_HANDLE_VALUE, "CreateFileA(client) failed: %lu", GetLastError());
|
|
TEST_CHECK(WaitForSingleObject(args->proceedEvent, 1000) == WAIT_OBJECT_0);
|
|
static const char payload[] = "PING!";
|
|
DWORD written = 0;
|
|
TEST_CHECK(WriteFile(client, payload, (DWORD)(sizeof(payload) - 1), &written, NULL));
|
|
TEST_CHECK_EQ(sizeof(payload) - 1, written);
|
|
CloseHandle(client);
|
|
return 0;
|
|
}
|
|
|
|
static void write_fixture_file(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
const char contents[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
DWORD written = 0;
|
|
TEST_CHECK(WriteFile(file, contents, (DWORD)(sizeof(contents) - 1), &written, NULL));
|
|
TEST_CHECK_EQ(sizeof(contents) - 1, written);
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_overlapped_requires_overlapped_structure(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
char buffer[8] = {0};
|
|
DWORD bytesRead = 0xFFFFFFFFu;
|
|
SetLastError(0);
|
|
TEST_CHECK(!ReadFile(file, buffer, sizeof(buffer), &bytesRead, NULL));
|
|
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
|
TEST_CHECK_EQ(0U, bytesRead);
|
|
|
|
static const char payload[] = "data";
|
|
DWORD bytesWritten = 0xFFFFFFFFu;
|
|
SetLastError(0);
|
|
TEST_CHECK(!WriteFile(file, payload, (DWORD)(sizeof(payload) - 1), &bytesWritten, NULL));
|
|
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
|
TEST_CHECK_EQ(0U, bytesWritten);
|
|
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_synchronous_overlapped_read(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.Offset = 5;
|
|
|
|
char buffer[16] = {0};
|
|
DWORD bytesRead = 0;
|
|
TEST_CHECK(ReadFile(file, buffer, 7, &bytesRead, &ov));
|
|
TEST_CHECK_EQ(7, bytesRead);
|
|
buffer[7] = '\0';
|
|
TEST_CHECK_STR_EQ("56789AB", buffer);
|
|
|
|
DWORD pos = SetFilePointer(file, 0, NULL, FILE_CURRENT);
|
|
TEST_CHECK_EQ(12, (int)pos);
|
|
|
|
unsigned long long trackedOffset = ((unsigned long long)ov.OffsetHigh << 32) | ov.Offset;
|
|
// Wine leaves OVERLAPPED.Offset unchanged for synchronous handles, even though the Win32 docs state the runtime
|
|
// should advance both the file pointer and the OVERLAPPED offsets. We intentionally skip asserting the offset here
|
|
// so the fixture passes under both wibo and wine. TEST_CHECK_U64_EQ(12ULL, trackedOffset);
|
|
(void)trackedOffset;
|
|
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_overlapped_read_with_event(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.Offset = 10;
|
|
ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(ov.hEvent != NULL);
|
|
|
|
char buffer[16] = {0};
|
|
BOOL issued = ReadFile(file, buffer, 6, NULL, &ov);
|
|
if (!issued) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
}
|
|
|
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
|
|
|
DWORD transferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, FALSE));
|
|
TEST_CHECK_EQ(6U, transferred);
|
|
buffer[6] = '\0';
|
|
TEST_CHECK_STR_EQ("ABCDEF", buffer);
|
|
|
|
TEST_CHECK(CloseHandle(ov.hEvent));
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_overlapped_read_without_event(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.Offset = 4;
|
|
|
|
char buffer[16] = {0};
|
|
BOOL issued = ReadFile(file, buffer, 8, NULL, &ov);
|
|
if (!issued) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
DWORD transferred = 0xFFFFFFFFU;
|
|
BOOL ready = GetOverlappedResult(file, &ov, &transferred, FALSE);
|
|
if (!ready) {
|
|
TEST_CHECK_EQ(ERROR_IO_INCOMPLETE, GetLastError());
|
|
TEST_CHECK_EQ(0xFFFFFFFFU, transferred); // untouched while pending
|
|
} else {
|
|
TEST_CHECK_EQ(8U, transferred);
|
|
}
|
|
}
|
|
|
|
DWORD transferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, TRUE));
|
|
TEST_CHECK_EQ(8U, transferred);
|
|
buffer[8] = '\0';
|
|
TEST_CHECK_STR_EQ("456789AB", buffer);
|
|
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_overlapped_eof(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.Offset = 80; /* beyond end */
|
|
ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(ov.hEvent != NULL);
|
|
|
|
char buffer[8] = {0};
|
|
BOOL issued = ReadFile(file, buffer, sizeof(buffer), NULL, &ov);
|
|
if (!issued) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
}
|
|
|
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
|
|
|
DWORD transferred = 1234;
|
|
TEST_CHECK(!GetOverlappedResult(file, &ov, &transferred, FALSE));
|
|
TEST_CHECK_EQ(ERROR_HANDLE_EOF, GetLastError());
|
|
TEST_CHECK_EQ(0U, transferred);
|
|
|
|
TEST_CHECK(CloseHandle(ov.hEvent));
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_getoverlappedresult_manual_event_signal(void) {
|
|
static const char *pipeName = "\\\\.\\pipe\\wibo_manual_event";
|
|
HANDLE pipe = CreateNamedPipeA(pipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
|
PIPE_TYPE_BYTE | PIPE_WAIT, 1, 0, 0, 0, NULL);
|
|
TEST_CHECK_MSG(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed: %lu", GetLastError());
|
|
|
|
HANDLE serverReady = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
HANDLE proceedWrite = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(serverReady != NULL && proceedWrite != NULL);
|
|
|
|
struct ManualEventWriterArgs writerArgs = {pipeName, serverReady, proceedWrite};
|
|
HANDLE writerThread = CreateThread(NULL, 0, manual_event_writer_thread, &writerArgs, 0, NULL);
|
|
TEST_CHECK(writerThread != NULL);
|
|
|
|
OVERLAPPED connectOv = {0};
|
|
connectOv.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(connectOv.hEvent != NULL);
|
|
BOOL connectIssued = ConnectNamedPipe(pipe, &connectOv);
|
|
if (!connectIssued) {
|
|
DWORD err = GetLastError();
|
|
TEST_CHECK_MSG(err == ERROR_IO_PENDING || err == ERROR_PIPE_CONNECTED, "ConnectNamedPipe err=%lu", err);
|
|
}
|
|
TEST_CHECK(SetEvent(serverReady));
|
|
if (!connectIssued) {
|
|
TEST_CHECK(WaitForSingleObject(connectOv.hEvent, 1000) == WAIT_OBJECT_0);
|
|
}
|
|
CloseHandle(connectOv.hEvent);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(ov.hEvent != NULL);
|
|
|
|
char buffer[8] = {0};
|
|
BOOL issued = ReadFile(pipe, buffer, sizeof(buffer), NULL, &ov);
|
|
TEST_CHECK(!issued);
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
|
|
DWORD transferred = 0xDEADBEEFu;
|
|
TEST_CHECK(SetEvent(ov.hEvent));
|
|
SetLastError(0xDEADBEEFu);
|
|
DWORD start = GetTickCount();
|
|
BOOL ready = GetOverlappedResult(pipe, &ov, &transferred, TRUE);
|
|
DWORD elapsed = GetTickCount() - start;
|
|
TEST_CHECK_MSG(elapsed < 1000, "GetOverlappedResult waited unexpectedly long (%lu ms)", elapsed);
|
|
if (!ready) {
|
|
TEST_CHECK_EQ(ERROR_IO_INCOMPLETE, GetLastError());
|
|
TEST_CHECK_EQ(0xDEADBEEFu, transferred);
|
|
} else {
|
|
TEST_CHECK_EQ(STATUS_PENDING, (DWORD)ov.Internal);
|
|
}
|
|
|
|
TEST_CHECK(ResetEvent(ov.hEvent));
|
|
TEST_CHECK(SetEvent(proceedWrite));
|
|
TEST_CHECK(WaitForSingleObject(writerThread, 1000) == WAIT_OBJECT_0);
|
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
|
|
|
DWORD finalTransferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(pipe, &ov, &finalTransferred, TRUE));
|
|
TEST_CHECK_EQ(5U, finalTransferred);
|
|
|
|
TEST_CHECK(CloseHandle(writerThread));
|
|
TEST_CHECK(CloseHandle(proceedWrite));
|
|
TEST_CHECK(CloseHandle(serverReady));
|
|
TEST_CHECK(CloseHandle(ov.hEvent));
|
|
TEST_CHECK(CloseHandle(pipe));
|
|
}
|
|
|
|
static void test_getoverlappedresult_non_overlapped_handle(void) {
|
|
static const char *pipeName = "\\\\.\\pipe\\wibo_sync_pipe";
|
|
HANDLE pipe = CreateNamedPipeA(pipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 0, 0, 0, NULL);
|
|
TEST_CHECK_MSG(pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed: %lu", GetLastError());
|
|
|
|
HANDLE serverReady = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(serverReady != NULL);
|
|
|
|
struct SyncWriterArgs writerArgs = {pipeName, serverReady};
|
|
HANDLE writerThread = CreateThread(NULL, 0, sync_writer_thread, &writerArgs, 0, NULL);
|
|
TEST_CHECK(writerThread != NULL);
|
|
|
|
TEST_CHECK(SetEvent(serverReady));
|
|
BOOL connected = ConnectNamedPipe(pipe, NULL);
|
|
if (!connected) {
|
|
DWORD err = GetLastError();
|
|
TEST_CHECK_EQ(ERROR_PIPE_CONNECTED, err);
|
|
}
|
|
|
|
HANDLE readStarted = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(readStarted != NULL);
|
|
|
|
OVERLAPPED ov = {0};
|
|
struct SyncReaderArgs readerArgs = {pipe, &ov, readStarted, 5, 0, FALSE};
|
|
HANDLE readerThread = CreateThread(NULL, 0, sync_reader_thread, &readerArgs, 0, NULL);
|
|
TEST_CHECK(readerThread != NULL);
|
|
|
|
TEST_CHECK(WaitForSingleObject(readStarted, 1000) == WAIT_OBJECT_0);
|
|
|
|
struct GetOverlappedWaitArgs waitArgs = {pipe, &ov, 0, FALSE, 0};
|
|
HANDLE waitThread = CreateThread(NULL, 0, getoverlapped_wait_thread, &waitArgs, 0, NULL);
|
|
TEST_CHECK(waitThread != NULL);
|
|
|
|
TEST_CHECK(WaitForSingleObject(readerThread, 5000) == WAIT_OBJECT_0);
|
|
TEST_CHECK(readerArgs.readSucceeded);
|
|
TEST_CHECK_EQ(5U, readerArgs.bytesRead);
|
|
|
|
TEST_CHECK(WaitForSingleObject(waitThread, 5000) == WAIT_OBJECT_0);
|
|
TEST_CHECK(waitArgs.result);
|
|
TEST_CHECK_EQ(ERROR_SUCCESS, waitArgs.error);
|
|
TEST_CHECK_EQ(5U, waitArgs.bytesTransferred);
|
|
|
|
TEST_CHECK(WaitForSingleObject(writerThread, 5000) == WAIT_OBJECT_0);
|
|
TEST_CHECK(CloseHandle(waitThread));
|
|
TEST_CHECK(CloseHandle(readerThread));
|
|
TEST_CHECK(CloseHandle(readStarted));
|
|
TEST_CHECK(CloseHandle(writerThread));
|
|
TEST_CHECK(CloseHandle(serverReady));
|
|
TEST_CHECK(CloseHandle(pipe));
|
|
}
|
|
|
|
static void test_getoverlappedresult_pending(void) {
|
|
OVERLAPPED ov = {0};
|
|
ov.Internal = STATUS_PENDING;
|
|
ov.InternalHigh = 42;
|
|
DWORD transferred = 0;
|
|
TEST_CHECK(!GetOverlappedResult(NULL, &ov, &transferred, FALSE));
|
|
TEST_CHECK_EQ(ERROR_IO_INCOMPLETE, GetLastError());
|
|
TEST_CHECK_EQ(0U, transferred); // No update if the operation is still pending
|
|
}
|
|
|
|
static void test_overlapped_multiple_reads(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov1 = {0};
|
|
OVERLAPPED ov2 = {0};
|
|
ov1.Offset = 0;
|
|
ov2.Offset = 16;
|
|
ov1.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
ov2.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
TEST_CHECK(ov1.hEvent != NULL);
|
|
TEST_CHECK(ov2.hEvent != NULL);
|
|
|
|
char head[8] = {0};
|
|
char tail[8] = {0};
|
|
|
|
BOOL issued1 = ReadFile(file, head, 5, NULL, &ov1);
|
|
if (!issued1) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
}
|
|
|
|
BOOL issued2 = ReadFile(file, tail, 5, NULL, &ov2);
|
|
if (!issued2) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
}
|
|
|
|
HANDLE events[2] = {ov1.hEvent, ov2.hEvent};
|
|
DWORD waitResult = WaitForMultipleObjects(2, events, TRUE, 1000);
|
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
|
|
|
DWORD transferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(file, &ov1, &transferred, FALSE));
|
|
TEST_CHECK_EQ(5U, transferred);
|
|
head[5] = '\0';
|
|
TEST_CHECK_STR_EQ("01234", head);
|
|
|
|
transferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(file, &ov2, &transferred, FALSE));
|
|
TEST_CHECK_EQ(5U, transferred);
|
|
tail[5] = '\0';
|
|
TEST_CHECK_STR_EQ("GHIJK", tail);
|
|
|
|
TEST_CHECK(CloseHandle(ov2.hEvent));
|
|
TEST_CHECK(CloseHandle(ov1.hEvent));
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_getoverlappedresult_wait(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.Offset = 20;
|
|
ov.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
TEST_CHECK(ov.hEvent != NULL);
|
|
|
|
char buffer[8] = {0};
|
|
BOOL issued = ReadFile(file, buffer, 6, NULL, &ov);
|
|
if (!issued) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
}
|
|
|
|
DWORD transferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, TRUE));
|
|
TEST_CHECK_EQ(6U, transferred);
|
|
buffer[6] = '\0';
|
|
TEST_CHECK_STR_EQ("KLMNOP", buffer);
|
|
|
|
TEST_CHECK(CloseHandle(ov.hEvent));
|
|
TEST_CHECK(CloseHandle(file));
|
|
}
|
|
|
|
static void test_overlapped_write(void) {
|
|
HANDLE file = CreateFileA(g_tempFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
TEST_CHECK(file != INVALID_HANDLE_VALUE);
|
|
|
|
OVERLAPPED ov = {0};
|
|
ov.Offset = 2;
|
|
ov.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
|
TEST_CHECK(ov.hEvent != NULL);
|
|
|
|
const char patch[] = "zz";
|
|
BOOL issued = WriteFile(file, patch, (DWORD)(sizeof(patch) - 1), NULL, &ov);
|
|
if (!issued) {
|
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
|
}
|
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
|
|
|
DWORD transferred = 0;
|
|
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, FALSE));
|
|
TEST_CHECK_EQ((DWORD)(sizeof(patch) - 1), transferred);
|
|
|
|
TEST_CHECK(CloseHandle(ov.hEvent));
|
|
TEST_CHECK(CloseHandle(file));
|
|
|
|
HANDLE verify = CreateFileA(g_tempFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
TEST_CHECK(verify != INVALID_HANDLE_VALUE);
|
|
|
|
TEST_CHECK(SetFilePointer(verify, 2, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER);
|
|
char buffer[3] = {0};
|
|
DWORD bytesRead = 0;
|
|
TEST_CHECK(ReadFile(verify, buffer, sizeof(patch) - 1, &bytesRead, NULL));
|
|
TEST_CHECK_EQ((DWORD)(sizeof(patch) - 1), bytesRead);
|
|
TEST_CHECK(buffer[0] == 'z' && buffer[1] == 'z');
|
|
|
|
TEST_CHECK(CloseHandle(verify));
|
|
}
|
|
|
|
int main(void) {
|
|
char tempPath[MAX_PATH] = {0};
|
|
DWORD len = GetTempPathA((DWORD)sizeof(tempPath), tempPath);
|
|
TEST_CHECK_MSG(len > 0 && len < sizeof(tempPath), "GetTempPathA failed: %lu", GetLastError());
|
|
TEST_CHECK_MSG(GetTempFileNameA(tempPath, "wbo", 0, g_tempFilename) != 0,
|
|
"GetTempFileNameA failed: %lu", GetLastError());
|
|
DeleteFileA(g_tempFilename);
|
|
write_fixture_file();
|
|
test_synchronous_overlapped_read();
|
|
test_overlapped_requires_overlapped_structure();
|
|
test_overlapped_read_with_event();
|
|
test_overlapped_read_without_event();
|
|
test_overlapped_eof();
|
|
test_getoverlappedresult_pending();
|
|
test_overlapped_multiple_reads();
|
|
test_getoverlappedresult_wait();
|
|
test_overlapped_write();
|
|
test_getoverlappedresult_manual_event_signal();
|
|
test_getoverlappedresult_non_overlapped_handle();
|
|
TEST_CHECK(DeleteFileA(g_tempFilename));
|
|
return 0;
|
|
}
|