From cd9c73cf39195b585c90fcaee182ebdde177bf10 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sun, 20 Apr 2014 13:44:55 +0000 Subject: [PATCH] [NTDLL_WINETEST] * Sync with Wine 1.7.17. CORE-8080 svn path=/trunk/; revision=62842 --- rostests/winetests/ntdll/CMakeLists.txt | 2 +- rostests/winetests/ntdll/atom.c | 6 +- rostests/winetests/ntdll/change.c | 6 +- rostests/winetests/ntdll/directory.c | 4 +- rostests/winetests/ntdll/error.c | 6 +- rostests/winetests/ntdll/exception.c | 150 ++++- rostests/winetests/ntdll/file.c | 717 ++++++++++++++++++------ rostests/winetests/ntdll/generated.c | 45 -- rostests/winetests/ntdll/info.c | 43 +- rostests/winetests/ntdll/om.c | 2 +- rostests/winetests/ntdll/path.c | 45 +- rostests/winetests/ntdll/pipe.c | 4 +- rostests/winetests/ntdll/port.c | 42 +- rostests/winetests/ntdll/reg.c | 4 +- rostests/winetests/ntdll/rtl.c | 58 ++ rostests/winetests/ntdll/rtlstr.c | 527 +++++++++++++++++ rostests/winetests/ntdll/string.c | 36 ++ rostests/winetests/ntdll/testlist.c | 5 +- rostests/winetests/ntdll/time.c | 4 +- 19 files changed, 1394 insertions(+), 312 deletions(-) diff --git a/rostests/winetests/ntdll/CMakeLists.txt b/rostests/winetests/ntdll/CMakeLists.txt index e9020f410fa..872874c3da7 100644 --- a/rostests/winetests/ntdll/CMakeLists.txt +++ b/rostests/winetests/ntdll/CMakeLists.txt @@ -1,7 +1,7 @@ remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502) -add_definitions(-D__ROS_LONG64__) +add_definitions(-D__WINESRC__) list(APPEND SOURCE atom.c diff --git a/rostests/winetests/ntdll/atom.c b/rostests/winetests/ntdll/atom.c index 1741f55963c..0fed6308e33 100755 --- a/rostests/winetests/ntdll/atom.c +++ b/rostests/winetests/ntdll/atom.c @@ -25,7 +25,7 @@ #include #include "ntstatus.h" -/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro +/* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro * definition errors when we get to winnt.h */ #define WIN32_NO_STATUS @@ -432,7 +432,7 @@ static void test_Global(void) { NTSTATUS res; RTL_ATOM atom; - ULONG ptr[(sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR) + sizeof(ULONG)) / sizeof(ULONG)]; + char ptr[sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR)]; ATOM_BASIC_INFORMATION* abi = (ATOM_BASIC_INFORMATION*)ptr; ULONG ptr_size = sizeof(ATOM_BASIC_INFORMATION) + 255 * sizeof(WCHAR); @@ -445,7 +445,7 @@ static void test_Global(void) memset( ptr, 0xcc, sizeof(ptr) ); res = pNtQueryInformationAtom( atom, AtomBasicInformation, (void*)ptr, ptr_size, NULL ); - ok(!res, "atom lookup failed with status = 0x%x\n", res); + ok(!res, "atom lookup\n"); ok(!lstrcmpW(abi->Name, testAtom1), "ok strings\n"); ok(abi->NameLength == lstrlenW(testAtom1) * sizeof(WCHAR), "wrong string length\n"); ok(abi->Name[lstrlenW(testAtom1)] == 0, "wrong string termination %x\n", abi->Name[lstrlenW(testAtom1)]); diff --git a/rostests/winetests/ntdll/change.c b/rostests/winetests/ntdll/change.c index 297af9ec11f..84e281c0235 100644 --- a/rostests/winetests/ntdll/change.c +++ b/rostests/winetests/ntdll/change.c @@ -69,7 +69,7 @@ static void test_ntncdf(void) OPEN_EXISTING, fflags, NULL); ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); - hEvent = CreateEvent( NULL, 0, 0, NULL ); + hEvent = CreateEventA( NULL, 0, 0, NULL ); r = pNtNotifyChangeDirectoryFile(hdir,NULL,NULL,NULL,&iosb,NULL,0,0,0); ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n"); @@ -197,7 +197,7 @@ static void test_ntncdf_async(void) OPEN_EXISTING, fflags, NULL); ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); - hEvent = CreateEvent( NULL, 0, 0, NULL ); + hEvent = CreateEventA( NULL, 0, 0, NULL ); filter = FILE_NOTIFY_CHANGE_FILE_NAME; filter |= FILE_NOTIFY_CHANGE_DIR_NAME; @@ -312,7 +312,7 @@ static void test_ntncdf_async(void) START_TEST(change) { - HMODULE hntdll = GetModuleHandle("ntdll"); + HMODULE hntdll = GetModuleHandleA("ntdll"); if (!hntdll) { win_skip("not running on NT, skipping test\n"); diff --git a/rostests/winetests/ntdll/directory.c b/rostests/winetests/ntdll/directory.c index f495fb33997..f190ff452d5 100644 --- a/rostests/winetests/ntdll/directory.c +++ b/rostests/winetests/ntdll/directory.c @@ -120,11 +120,11 @@ static void tear_down_attribute_test(const char *testdirA) continue; sprintf(buf, "%s\\%s", testdirA, testfiles[i].name); if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { - ret = RemoveDirectory(buf); + ret = RemoveDirectoryA(buf); ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), "Failed to rmdir %s, error %d\n", buf, GetLastError()); } else { - ret = DeleteFile(buf); + ret = DeleteFileA(buf); ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), "Failed to rm %s, error %d\n", buf, GetLastError()); } diff --git a/rostests/winetests/ntdll/error.c b/rostests/winetests/ntdll/error.c index d9c83b3dcac..862f0a96ff6 100755 --- a/rostests/winetests/ntdll/error.c +++ b/rostests/winetests/ntdll/error.c @@ -50,7 +50,7 @@ static ULONG (WINAPI *pRtlNtStatusToDosError)(NTSTATUS Status); static int strict; -static int prepare_test(void) +static BOOL prepare_test(void) { HMODULE ntdll; int argc; @@ -61,12 +61,12 @@ static int prepare_test(void) if (!pRtlNtStatusToDosError) { win_skip("RtlNtStatusToDosError is not available\n"); - return 0; + return FALSE; } argc = winetest_get_mainargs(&argv); strict=(argc >= 3 && strcmp(argv[2],"strict")==0); - return 1; + return TRUE; } static void cmp_call(NTSTATUS win_nt, ULONG win32, const char* message) diff --git a/rostests/winetests/ntdll/exception.c b/rostests/winetests/ntdll/exception.c index ac138055347..1e45d827286 100644 --- a/rostests/winetests/ntdll/exception.c +++ b/rostests/winetests/ntdll/exception.c @@ -51,6 +51,13 @@ static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); +#if defined(__x86_64__) +static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64); +static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*); +static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR); +static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*); +#endif + #ifdef __i386__ #ifndef __WINE_WINTRNL_H @@ -314,7 +321,7 @@ static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR return ExceptionContinueSearch; /* Eip in context is decreased by 1 - * Increase it again, else execution will continue in the middle of a instruction */ + * Increase it again, else execution will continue in the middle of an instruction */ if(rec->ExceptionCode == EXCEPTION_BREAKPOINT && (context->Eip == (DWORD)code_mem + 0xa)) context->Eip += 1; return ExceptionContinueExecution; @@ -731,7 +738,7 @@ static void test_debugger(void) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; - STARTUPINFO si = { 0 }; + STARTUPINFOA si = { 0 }; DEBUG_EVENT de; DWORD continuestatus; PVOID code_mem_address = NULL; @@ -748,7 +755,7 @@ static void test_debugger(void) } sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); - ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %u\n", GetLastError()); if (!ret) return; @@ -796,7 +803,7 @@ static void test_debugger(void) if (counter > 100) { - ok(FALSE, "got way too many exceptions, probably caught in a infinite loop, terminating child\n"); + ok(FALSE, "got way too many exceptions, probably caught in an infinite loop, terminating child\n"); pNtTerminateProcess(pi.hProcess, 1); } else if (counter >= 2) /* skip startup breakpoint */ @@ -1057,7 +1064,7 @@ static DWORD dpe_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION static void test_dpe_exceptions(void) { - static char single_ret[] = {0xC3}; + static const BYTE single_ret[] = {0xC3}; struct dpe_exception_info info; NTSTATUS stat; BOOL has_hw_support; @@ -1065,7 +1072,7 @@ static void test_dpe_exceptions(void) DWORD val; ULONG len; - /* Query DEP with len to small */ + /* Query DEP with len too small */ stat = pNtQueryInformationProcess(GetCurrentProcess(), ProcessExecuteFlags, &val, sizeof val - 1, &len); if(stat == STATUS_INVALID_INFO_CLASS) { @@ -1447,6 +1454,122 @@ static void test_virtual_unwind(void) call_virtual_unwind( i, &tests[i] ); } +static RUNTIME_FUNCTION* CALLBACK dynamic_unwind_callback( DWORD64 pc, PVOID context ) +{ + static const int code_offset = 1024; + static RUNTIME_FUNCTION runtime_func; + (*(DWORD *)context)++; + + runtime_func.BeginAddress = code_offset + 16; + runtime_func.EndAddress = code_offset + 32; + runtime_func.UnwindData = 0; + return &runtime_func; +} + +static void test_dynamic_unwind(void) +{ + static const int code_offset = 1024; + char buf[sizeof(RUNTIME_FUNCTION) + 4]; + RUNTIME_FUNCTION *runtime_func, *func; + ULONG_PTR table, base; + DWORD count; + + /* Test RtlAddFunctionTable with aligned RUNTIME_FUNCTION pointer */ + runtime_func = (RUNTIME_FUNCTION *)buf; + runtime_func->BeginAddress = code_offset; + runtime_func->EndAddress = code_offset + 16; + runtime_func->UnwindData = 0; + ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ), + "RtlAddFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func ); + + /* Lookup function outside of any function table */ + base = 0xdeadbeef; + func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL ); + ok( func == NULL, + "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func ); + ok( base == 0xdeadbeef, + "RtlLookupFunctionEntry modified base address, expected: 0xdeadbeef, got: %lx\n", base ); + + /* Test with pointer inside of our function */ + base = 0xdeadbeef; + func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL ); + ok( func == runtime_func, + "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func ); + ok( base == (ULONG_PTR)code_mem, + "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base ); + + /* Test RtlDeleteFunctionTable */ + ok( pRtlDeleteFunctionTable( runtime_func ), + "RtlDeleteFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func ); + ok( !pRtlDeleteFunctionTable( runtime_func ), + "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func ); + + /* Unaligned RUNTIME_FUNCTION pointer */ + runtime_func = (RUNTIME_FUNCTION *)((ULONG_PTR)buf | 0x3); + runtime_func->BeginAddress = code_offset; + runtime_func->EndAddress = code_offset + 16; + runtime_func->UnwindData = 0; + ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ), + "RtlAddFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func ); + ok( pRtlDeleteFunctionTable( runtime_func ), + "RtlDeleteFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func ); + + /* Attempt to insert the same entry twice */ + runtime_func = (RUNTIME_FUNCTION *)buf; + runtime_func->BeginAddress = code_offset; + runtime_func->EndAddress = code_offset + 16; + runtime_func->UnwindData = 0; + ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ), + "RtlAddFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func ); + ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ), + "RtlAddFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func ); + ok( pRtlDeleteFunctionTable( runtime_func ), + "RtlDeleteFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func ); + ok( pRtlDeleteFunctionTable( runtime_func ), + "RtlDeleteFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func ); + ok( !pRtlDeleteFunctionTable( runtime_func ), + "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func ); + + /* Test RtlInstallFunctionTableCallback with both low bits unset */ + table = (ULONG_PTR)code_mem; + ok( !pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ), + "RtlInstallFunctionTableCallback returned success for table = %lx\n", table ); + + /* Test RtlInstallFunctionTableCallback with both low bits set */ + table = (ULONG_PTR)code_mem | 0x3; + ok( pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ), + "RtlInstallFunctionTableCallback failed for table = %lx\n", table ); + + /* Lookup function outside of any function table */ + count = 0; + base = 0xdeadbeef; + func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 32, &base, NULL ); + ok( func == NULL, + "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func ); + ok( base == 0xdeadbeef, + "RtlLookupFunctionEntry modified base address, expected: 0xdeadbeef, got: %lx\n", base ); + ok( !count, + "RtlLookupFunctionEntry issued %d unexpected calls to dynamic_unwind_callback\n", count ); + + /* Test with pointer inside of our function */ + count = 0; + base = 0xdeadbeef; + func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 24, &base, NULL ); + ok( func != NULL && func->BeginAddress == code_offset + 16 && func->EndAddress == code_offset + 32, + "RtlLookupFunctionEntry didn't return expected function, got: %p\n", func ); + ok( base == (ULONG_PTR)code_mem, + "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base ); + ok( count == 1, + "RtlLookupFunctionEntry issued %d calls to dynamic_unwind_callback, expected: 1\n", count ); + + /* Clean up again */ + ok( pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ), + "RtlDeleteFunctionTable failed for table = %p\n", (PVOID)table ); + ok( !pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ), + "RtlDeleteFunctionTable returned success for nonexistent table = %p\n", (PVOID)table ); + +} + #endif /* __x86_64__ */ START_TEST(exception) @@ -1473,7 +1596,7 @@ START_TEST(exception) "NtQueryInformationProcess" ); pNtSetInformationProcess = (void*)GetProcAddress( hntdll, "NtSetInformationProcess" ); - pIsWow64Process = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process"); + pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); #ifdef __i386__ if (!pNtCurrentTeb) @@ -1534,9 +1657,22 @@ START_TEST(exception) test_dpe_exceptions(); #elif defined(__x86_64__) + pRtlAddFunctionTable = (void *)GetProcAddress( hntdll, + "RtlAddFunctionTable" ); + pRtlDeleteFunctionTable = (void *)GetProcAddress( hntdll, + "RtlDeleteFunctionTable" ); + pRtlInstallFunctionTableCallback = (void *)GetProcAddress( hntdll, + "RtlInstallFunctionTableCallback" ); + pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll, + "RtlLookupFunctionEntry" ); test_virtual_unwind(); + if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry) + test_dynamic_unwind(); + else + skip( "Dynamic unwind functions not found\n" ); + #endif VirtualFree(code_mem, 0, MEM_FREE); diff --git a/rostests/winetests/ntdll/file.c b/rostests/winetests/ntdll/file.c index ea152d18467..de64a856c99 100644 --- a/rostests/winetests/ntdll/file.c +++ b/rostests/winetests/ntdll/file.c @@ -89,7 +89,7 @@ static inline BOOL is_signaled( HANDLE obj ) static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size ) { - *read = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT, + *read = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT, 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL); ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); @@ -782,8 +782,7 @@ static void read_file_test(void) iosb.Information = 0xdeadbeef; offset.QuadPart = strlen(text) + 2; status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL ); -todo_wine - ok(status == STATUS_PENDING || broken(status == STATUS_END_OF_FILE) /* before Vista */, "expected STATUS_PENDING, got %#x\n", status); + ok(status == STATUS_PENDING || status == STATUS_END_OF_FILE /* before Vista */, "expected STATUS_PENDING or STATUS_END_OF_FILE, got %#x\n", status); if (status == STATUS_PENDING) /* vista */ { WaitForSingleObject( event, 1000 ); @@ -837,9 +836,9 @@ todo_wine ResetEvent( event ); status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL ); ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status ); - todo_wine ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status ); - todo_wine ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - todo_wine ok( is_signaled( event ), "event is not signaled\n" ); + ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status ); + ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); + ok( is_signaled( event ), "event is not signaled\n" ); ok( !apc_count, "apc was called\n" ); SleepEx( 1, TRUE ); /* alertable sleep */ ok( !apc_count, "apc was called\n" ); @@ -851,43 +850,93 @@ todo_wine static void append_file_test(void) { - const char text[] = "foobar"; + static const char text[6] = "foobar"; HANDLE handle; NTSTATUS status; IO_STATUS_BLOCK iosb; - DWORD written; - char path[MAX_PATH], buffer[MAX_PATH]; + LARGE_INTEGER offset; + char path[MAX_PATH], buffer[MAX_PATH], buf[16]; + DWORD ret; GetTempPathA( MAX_PATH, path ); GetTempFileNameA( path, "foo", 0, buffer ); - /* It is possible to open a file with only FILE_APPEND_DATA access flags. - It matches the O_WRONLY|O_APPEND open() posix behavior */ - handle = CreateFileA(buffer, FILE_APPEND_DATA, 0, NULL, CREATE_ALWAYS, - FILE_FLAG_DELETE_ON_CLOSE, 0); - ok( handle != INVALID_HANDLE_VALUE, "Failed to create a temp file in FILE_APPEND_DATA mode.\n" ); - if(handle == INVALID_HANDLE_VALUE) - { - skip("Couldn't create a temporary file, skipping FILE_APPEND_DATA test\n"); - return; - } - U(iosb).Status = STATUS_PENDING; - iosb.Information = 0; + handle = CreateFileA(buffer, FILE_WRITE_DATA, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError()); - status = pNtWriteFile(handle, NULL, NULL, NULL, &iosb, - text, sizeof(text), NULL, NULL); - - if (status == STATUS_PENDING) - { - WaitForSingleObject( handle, 1000 ); - status = U(iosb).Status; - } - written = iosb.Information; - - todo_wine - ok(status == STATUS_SUCCESS && written == sizeof(text), "FILE_APPEND_DATA NtWriteFile failed\n"); + U(iosb).Status = -1; + iosb.Information = -1; + status = pNtWriteFile(handle, NULL, NULL, NULL, &iosb, text, 2, NULL, NULL); + ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); + ok(U(iosb).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iosb).Status); + ok(iosb.Information == 2, "expected 2, got %lu\n", iosb.Information); CloseHandle(handle); + + /* It is possible to open a file with only FILE_APPEND_DATA access flags. + It matches the O_WRONLY|O_APPEND open() posix behavior */ + handle = CreateFileA(buffer, FILE_APPEND_DATA, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError()); + + U(iosb).Status = -1; + iosb.Information = -1; + offset.QuadPart = 1; + status = pNtWriteFile(handle, NULL, NULL, NULL, &iosb, text + 2, 2, &offset, NULL); + ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); + ok(U(iosb).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iosb).Status); + ok(iosb.Information == 2, "expected 2, got %lu\n", iosb.Information); + + ret = SetFilePointer(handle, 0, NULL, FILE_CURRENT); + ok(ret == 4, "expected 4, got %u\n", ret); + + U(iosb).Status = -1; + iosb.Information = -1; + offset.QuadPart = 3; + status = pNtWriteFile(handle, NULL, NULL, NULL, &iosb, text + 4, 2, &offset, NULL); + ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); + ok(U(iosb).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iosb).Status); + ok(iosb.Information == 2, "expected 2, got %lu\n", iosb.Information); + + ret = SetFilePointer(handle, 0, NULL, FILE_CURRENT); + ok(ret == 6, "expected 6, got %u\n", ret); + + CloseHandle(handle); + + handle = CreateFileA(buffer, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError()); + + memset(buf, 0, sizeof(buf)); + U(iosb).Status = -1; + iosb.Information = -1; + offset.QuadPart = 0; + status = pNtReadFile(handle, 0, NULL, NULL, &iosb, buf, sizeof(buf), &offset, NULL); + ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); + ok(U(iosb).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iosb).Status); + ok(iosb.Information == 6, "expected 6, got %lu\n", iosb.Information); + buf[6] = 0; + ok(memcmp(buf, text, 6) == 0, "wrong file contents: %s\n", buf); + + U(iosb).Status = -1; + iosb.Information = -1; + offset.QuadPart = 0; + status = pNtWriteFile(handle, NULL, NULL, NULL, &iosb, text + 3, 3, &offset, NULL); + ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); + ok(U(iosb).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iosb).Status); + ok(iosb.Information == 3, "expected 3, got %lu\n", iosb.Information); + + memset(buf, 0, sizeof(buf)); + U(iosb).Status = -1; + iosb.Information = -1; + offset.QuadPart = 0; + status = pNtReadFile(handle, 0, NULL, NULL, &iosb, buf, sizeof(buf), &offset, NULL); + ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); + ok(U(iosb).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iosb).Status); + ok(iosb.Information == 6, "expected 6, got %lu\n", iosb.Information); + buf[6] = 0; + ok(memcmp(buf, "barbar", 6) == 0, "wrong file contents: %s\n", buf); + + CloseHandle(handle); + DeleteFileA(buffer); } static void nt_mailslot_test(void) @@ -1302,7 +1351,7 @@ static void test_file_both_information(void) static void test_file_disposition_information(void) { - char buffer[MAX_PATH + 16]; + char tmp_path[MAX_PATH], buffer[MAX_PATH + 16]; DWORD dirpos; HANDLE handle, handle2; NTSTATUS res; @@ -1310,8 +1359,10 @@ static void test_file_disposition_information(void) FILE_DISPOSITION_INFORMATION fdi; BOOL fileDeleted; + GetTempPathA( MAX_PATH, tmp_path ); + /* cannot set disposition on file not opened with delete access */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); res = pNtQueryInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation ); @@ -1326,7 +1377,7 @@ static void test_file_disposition_information(void) DeleteFileA( buffer ); /* can set disposition on file opened with proper access */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); fdi.DoDeleteFile = TRUE; @@ -1340,7 +1391,7 @@ static void test_file_disposition_information(void) DeleteFileA( buffer ); /* cannot set disposition on readonly file */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); fdi.DoDeleteFile = TRUE; @@ -1354,7 +1405,7 @@ static void test_file_disposition_information(void) DeleteFileA( buffer ); /* can set disposition on file and then reset it */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); fdi.DoDeleteFile = TRUE; @@ -1371,7 +1422,7 @@ static void test_file_disposition_information(void) DeleteFileA( buffer ); /* Delete-on-close flag doesn't change file disposition until a handle is closed */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); fdi.DoDeleteFile = FALSE; @@ -1384,7 +1435,7 @@ static void test_file_disposition_information(void) DeleteFileA( buffer ); /* Delete-on-close flag sets disposition when a handle is closed and then it could be changed back */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0); ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); ok( DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle2, 0, FALSE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" ); @@ -1399,7 +1450,7 @@ static void test_file_disposition_information(void) DeleteFileA( buffer ); /* can set disposition on a directory opened with proper access */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); DeleteFileA( buffer ); ok( CreateDirectoryA( buffer, NULL ), "CreateDirectory failed\n" ); handle = CreateFileA(buffer, DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); @@ -1415,7 +1466,7 @@ static void test_file_disposition_information(void) RemoveDirectoryA( buffer ); /* RemoveDirectory sets directory disposition and it can be undone */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); DeleteFileA( buffer ); ok( CreateDirectoryA( buffer, NULL ), "CreateDirectory failed\n" ); handle = CreateFileA(buffer, DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); @@ -1431,7 +1482,7 @@ static void test_file_disposition_information(void) RemoveDirectoryA( buffer ); /* cannot set disposition on a non-empty directory */ - GetTempFileNameA( ".", "dis", 0, buffer ); + GetTempFileNameA( tmp_path, "dis", 0, buffer ); DeleteFileA( buffer ); ok( CreateDirectoryA( buffer, NULL ), "CreateDirectory failed\n" ); handle = CreateFileA(buffer, DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); @@ -1921,53 +1972,81 @@ static void test_NtCreateFile(void) static void test_read_write(void) { - static const char contents[] = "1234567890abcd"; + static const char contents[14] = "1234567890abcd"; char buf[256]; HANDLE hfile; OVERLAPPED ovl; IO_STATUS_BLOCK iob; - DWORD ret, bytes, status; + DWORD ret, bytes, status, off; LARGE_INTEGER offset; + LONG i; - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtReadFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, "expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status); - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtWriteFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, "expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status); - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); hfile = create_temp_file(0); if (!hfile) return; - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL); ok(status == STATUS_INVALID_USER_BUFFER, "expected STATUS_INVALID_USER_BUFFER, got %#x\n", status); - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL); ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status); - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; - status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, sizeof(contents), NULL, NULL); + status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, 7, NULL, NULL); ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); - ok(iob.Information == sizeof(contents), "expected sizeof(contents), got %lu\n", iob.Information); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == 7, "expected 7, got %lu\n", iob.Information); + + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); + + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = (LONGLONG)-1 /* FILE_WRITE_TO_END_OF_FILE */; + status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents + 7, sizeof(contents) - 7, &offset, NULL); + ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == sizeof(contents) - 7, "expected sizeof(contents)-7, got %lu\n", iob.Information); + + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = ReadFile(INVALID_HANDLE_VALUE, buf, 0, &bytes, NULL); + ok(!ret, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, buf, 0, &bytes, NULL); + ok(ret, "ReadFile error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); @@ -1985,16 +2064,39 @@ static void test_read_write(void) ok(bytes == sizeof(contents), "bytes %u\n", bytes); ok(!memcmp(contents, buf, sizeof(contents)), "file contents mismatch\n"); + for (i = -20; i < -1; i++) + { + if (i == -2) continue; + + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = (LONGLONG)i; + status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, sizeof(contents), &offset, NULL); + ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + } + SetFilePointer(hfile, sizeof(contents) - 4, NULL, FILE_BEGIN); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, "DCBA", 4, &offset, NULL); ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); ok(iob.Information == 4, "expected 4, got %lu\n", iob.Information); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + + U(iob).Status = -1; + iob.Information = -1; + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), NULL, NULL); + ok(status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", status); + ok(U(iob).Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); bytes = 0; @@ -2005,6 +2107,9 @@ static void test_read_write(void) ok(!memcmp(contents, buf, sizeof(contents) - 4), "file contents mismatch\n"); ok(!memcmp(buf + sizeof(contents) - 4, "DCBA", 4), "file contents mismatch\n"); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); bytes = 0; @@ -2013,25 +2118,118 @@ static void test_read_write(void) ok(ret, "WriteFile error %d\n", GetLastError()); ok(bytes == sizeof(contents), "bytes %u\n", bytes); - iob.Status = -1; + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + + /* test reading beyond EOF */ + bytes = -1; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, buf, sizeof(buf), &bytes, NULL); + ok(ret, "ReadFile error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + + bytes = -1; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, buf, 0, &bytes, NULL); + ok(ret, "ReadFile error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + + bytes = -1; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, NULL, 0, &bytes, NULL); + ok(ret, "ReadFile error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + + S(U(ovl)).Offset = sizeof(contents); + S(U(ovl)).OffsetHigh = 0; + ovl.Internal = -1; + ovl.InternalHigh = -1; + ovl.hEvent = 0; + bytes = -1; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, buf, sizeof(buf), &bytes, &ovl); + ok(!ret, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_HANDLE_EOF, "expected ERROR_HANDLE_EOF, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + ok((NTSTATUS)ovl.Internal == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#lx\n", ovl.Internal); + ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + + S(U(ovl)).Offset = sizeof(contents); + S(U(ovl)).OffsetHigh = 0; + ovl.Internal = -1; + ovl.InternalHigh = -1; + ovl.hEvent = 0; + bytes = -1; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, buf, 0, &bytes, &ovl); + ok(ret, "ReadFile error %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); + ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + + U(iob).Status = -1; iob.Information = -1; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), NULL, NULL); ok(status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", status); -todo_wine - ok(iob.Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", iob.Status); -todo_wine + ok(U(iob).Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", U(iob).Status); ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); - iob.Status = -1; + U(iob).Status = -1; + iob.Information = -1; + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, 0, NULL, NULL); + ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = sizeof(contents); + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); + ok(status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", status); + ok(U(iob).Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = sizeof(contents); + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, 0, &offset, NULL); + ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); ok(status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", status); -todo_wine - ok(iob.Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", iob.Status); -todo_wine + ok(U(iob).Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", U(iob).Status); ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */; + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, 0, &offset, NULL); + ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + + for (i = -20; i < 0; i++) + { + if (i == -2) continue; + + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = (LONGLONG)i; + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); + ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + } + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); bytes = 0; @@ -2041,42 +2239,45 @@ todo_wine ok(bytes == sizeof(contents), "bytes %u\n", bytes); ok(!memcmp(contents, buf, sizeof(contents)), "file contents mismatch\n"); - iob.Status = -1; - iob.Information = -1; - status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), NULL, NULL); - ok(status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", status); -todo_wine - ok(iob.Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", iob.Status); -todo_wine - ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); ok(iob.Information == sizeof(contents), "expected sizeof(contents), got %lu\n", iob.Information); ok(!memcmp(contents, buf, sizeof(contents)), "file contents mismatch\n"); - iob.Status = -1; + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = sizeof(contents) - 4; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, "DCBA", 4, &offset, NULL); ok(status == STATUS_SUCCESS, "NtWriteFile error %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); ok(iob.Information == 4, "expected 4, got %lu\n", iob.Information); - iob.Status = -1; + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); ok(status == STATUS_SUCCESS, "NtReadFile error %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); ok(iob.Information == sizeof(contents), "expected sizeof(contents), got %lu\n", iob.Information); ok(!memcmp(contents, buf, sizeof(contents) - 4), "file contents mismatch\n"); ok(!memcmp(buf + sizeof(contents) - 4, "DCBA", 4), "file contents mismatch\n"); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + S(U(ovl)).Offset = sizeof(contents) - 4; S(U(ovl)).OffsetHigh = 0; ovl.hEvent = 0; @@ -2086,6 +2287,9 @@ todo_wine ok(ret, "WriteFile error %d\n", GetLastError()); ok(bytes == 4, "bytes %u\n", bytes); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + S(U(ovl)).Offset = 0; S(U(ovl)).OffsetHigh = 0; ovl.Internal = -1; @@ -2101,6 +2305,9 @@ todo_wine ok(!memcmp(contents, buf, sizeof(contents) - 4), "file contents mismatch\n"); ok(!memcmp(buf + sizeof(contents) - 4, "ABCD", 4), "file contents mismatch\n"); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == sizeof(contents), "expected sizeof(contents), got %u\n", off); + CloseHandle(hfile); hfile = create_temp_file(FILE_FLAG_OVERLAPPED); @@ -2108,58 +2315,64 @@ todo_wine bytes = 0xdeadbeef; SetLastError(0xdeadbeef); - ret = WriteFile(hfile, contents, sizeof(contents), &bytes, NULL); -todo_wine - ok(!ret, "WriteFile should fail\n"); -todo_wine - ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); -todo_wine + ret = ReadFile(INVALID_HANDLE_VALUE, buf, 0, &bytes, NULL); + ok(!ret, "ReadFile should fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); ok(bytes == 0, "bytes %u\n", bytes); - iob.Status = -1; + S(U(ovl)).Offset = 0; + S(U(ovl)).OffsetHigh = 0; + ovl.Internal = -1; + ovl.InternalHigh = -1; + ovl.hEvent = 0; + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + /* ReadFile return value depends on Windows version and testing it is not practical */ + ReadFile(hfile, buf, 0, &bytes, &ovl); + ok(bytes == 0, "bytes %u\n", bytes); + ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); + ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = WriteFile(hfile, contents, sizeof(contents), &bytes, NULL); + ok(!ret, "WriteFile should fail\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + + U(iob).Status = -1; iob.Information = -1; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, sizeof(contents), NULL, NULL); -todo_wine ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status); -todo_wine - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); -todo_wine + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); - iob.Status = -1; - iob.Information = -1; - offset.QuadPart = (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */; - status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, sizeof(contents), &offset, NULL); -todo_wine - ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status); -todo_wine - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); -todo_wine - ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + for (i = -20; i < -1; i++) + { + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = (LONGLONG)i; + status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, sizeof(contents), &offset, NULL); + ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + } - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, sizeof(contents), &offset, NULL); -todo_wine - ok(status == STATUS_PENDING || broken(status == STATUS_SUCCESS) /* see below */, "expected STATUS_PENDING, got %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); - ok(iob.Information == sizeof(contents), "expected sizeof(contents), got %lu\n", iob.Information); - /* even fully updated XP passes this test, but it looks like some VMs - * in a testbot get never updated, so overlapped IO is broken. Instead - * of fighting with broken tests and adding a bunch of broken() statements - * it's better to skip further tests completely. - */ - if (status != STATUS_PENDING) + ok(status == STATUS_PENDING || status == STATUS_SUCCESS /* before Vista */, "expected STATUS_PENDING or STATUS_SUCCESS, got %#x\n", status); + if (status == STATUS_PENDING) { -todo_wine - win_skip("broken overlapped IO implementation, update your OS\n"); - CloseHandle(hfile); - return; + ret = WaitForSingleObject(hfile, 3000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); } + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == sizeof(contents), "expected sizeof(contents), got %lu\n", iob.Information); - ret = WaitForSingleObject(hfile, 3000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); bytes = 0xdeadbeef; SetLastError(0xdeadbeef); @@ -2168,21 +2381,28 @@ todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); ok(bytes == 0, "bytes %u\n", bytes); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), NULL, NULL); ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status); - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); - iob.Status = -1; - iob.Information = -1; - offset.QuadPart = (LONGLONG)-2 /* FILE_USE_FILE_POINTER_POSITION */; - status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); - ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status); - ok(iob.Status == -1, "expected -1, got %#x\n", iob.Status); - ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + for (i = -20; i < 0; i++) + { + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = (LONGLONG)i; + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); + ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information); + } + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + + /* test reading beyond EOF */ offset.QuadPart = sizeof(contents); S(U(ovl)).Offset = offset.u.LowPart; S(U(ovl)).OffsetHigh = offset.u.HighPart; @@ -2193,52 +2413,131 @@ todo_wine SetLastError(0xdeadbeef); ret = ReadFile(hfile, buf, sizeof(buf), &bytes, &ovl); ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_IO_PENDING || broken(GetLastError() == ERROR_HANDLE_EOF), "expected ERROR_IO_PENDING, got %d\n", GetLastError()); - /* even fully updated XP passes this test, but it looks like some VMs - * in a testbot get never updated, so overlapped IO is broken. Instead - * of fighting with broken tests and adding a bunch of broken() statements - * it's better to skip further tests completely. - */ - if (GetLastError() != ERROR_IO_PENDING) - { - win_skip("broken overlapped IO implementation, update your OS\n"); - CloseHandle(hfile); - return; - } + ret = GetLastError(); + ok(ret == ERROR_IO_PENDING || ret == ERROR_HANDLE_EOF /* before Vista */, "expected ERROR_IO_PENDING or ERROR_HANDLE_EOF, got %d\n", ret); ok(bytes == 0, "bytes %u\n", bytes); - ok((NTSTATUS)ovl.Internal == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#lx\n", ovl.Internal); - ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + + if (ret == ERROR_IO_PENDING) + { + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); + ok(!ret, "GetOverlappedResult should report FALSE\n"); + ok(GetLastError() == ERROR_HANDLE_EOF, "expected ERROR_HANDLE_EOF, got %d\n", GetLastError()); + ok(bytes == 0, "expected 0, read %u\n", bytes); + ok((NTSTATUS)ovl.Internal == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#lx\n", ovl.Internal); + ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + } + + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + + offset.QuadPart = sizeof(contents); + S(U(ovl)).Offset = offset.u.LowPart; + S(U(ovl)).OffsetHigh = offset.u.HighPart; + ovl.Internal = -1; + ovl.InternalHigh = -1; + ovl.hEvent = 0; bytes = 0xdeadbeef; - ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); - ok(!ret, "GetOverlappedResult should report FALSE\n"); - ok(GetLastError() == ERROR_HANDLE_EOF, "expected ERROR_HANDLE_EOF, got %d\n", GetLastError()); - ok(bytes == 0, "expected 0, read %u\n", bytes); - ok((NTSTATUS)ovl.Internal == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#lx\n", ovl.Internal); - ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, buf, 0, &bytes, &ovl); + /* ReadFile return value depends on Windows version and testing it is not practical */ + if (!ret) +todo_wine + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); + ret = GetLastError(); + ok(bytes == 0, "bytes %u\n", bytes); - iob.Status = -1; + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + + if (ret == ERROR_IO_PENDING) + { + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); + ok(ret, "GetOverlappedResult should report TRUE\n"); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "expected 0, read %u\n", bytes); + ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); + ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + } + + offset.QuadPart = sizeof(contents); + S(U(ovl)).Offset = offset.u.LowPart; + S(U(ovl)).OffsetHigh = offset.u.HighPart; + ovl.Internal = -1; + ovl.InternalHigh = -1; + ovl.hEvent = 0; + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = ReadFile(hfile, NULL, 0, &bytes, &ovl); + /* ReadFile return value depends on Windows version and testing it is not practical */ + if (!ret) +todo_wine + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); + ret = GetLastError(); + ok(bytes == 0, "bytes %u\n", bytes); + + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + + if (ret == ERROR_IO_PENDING) + { + bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); + ok(ret, "GetOverlappedResult should report TRUE\n"); + ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(bytes == 0, "expected 0, read %u\n", bytes); + ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); + ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + } + + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = sizeof(contents); status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); - ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %#x\n", status); - ok(iob.Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", iob.Status); - ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + if (status == STATUS_PENDING) + { + ret = WaitForSingleObject(hfile, 3000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + ok(U(iob).Status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + } + else + { + ok(status == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#x\n", status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); + } - S(U(ovl)).Offset = offset.u.LowPart; - S(U(ovl)).OffsetHigh = offset.u.HighPart; - ovl.Internal = iob.Status; - ovl.InternalHigh = iob.Information; - ovl.hEvent = 0; - bytes = 0xdeadbeef; - ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); - ok(!ret, "GetOverlappedResult should report FALSE\n"); - ok(GetLastError() == ERROR_HANDLE_EOF, "expected ERROR_HANDLE_EOF, got %d\n", GetLastError()); - ok(bytes == 0, "expected 0, read %u\n", bytes); - ok((NTSTATUS)ovl.Internal == STATUS_END_OF_FILE, "expected STATUS_END_OF_FILE, got %#lx\n", ovl.Internal); - ok(ovl.InternalHigh == 0, "expected 0, got %lu\n", ovl.InternalHigh); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); - SetFilePointer(hfile, 0, NULL, FILE_BEGIN); + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = sizeof(contents); + status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, 0, &offset, NULL); + if (status == STATUS_PENDING) + { + ret = WaitForSingleObject(hfile, 3000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + } + else + { + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", status); + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); + ok(iob.Information == 0, "expected 0, got %lu\n", iob.Information); + } + + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); S(U(ovl)).Offset = 0; S(U(ovl)).OffsetHigh = 0; @@ -2248,12 +2547,19 @@ todo_wine bytes = 0; SetLastError(0xdeadbeef); ret = ReadFile(hfile, buf, sizeof(buf), &bytes, &ovl); - ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); - ok(bytes == 0, "bytes %u\n", bytes); + /* ReadFile return value depends on Windows version and testing it is not practical */ + if (!ret) + { + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + } + else ok(bytes == 14, "bytes %u\n", bytes); ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); ok(ovl.InternalHigh == sizeof(contents), "expected sizeof(contents), got %lu\n", ovl.InternalHigh); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + bytes = 0xdeadbeef; ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); ok(ret, "GetOverlappedResult error %d\n", GetLastError()); @@ -2262,30 +2568,51 @@ todo_wine ok(ovl.InternalHigh == sizeof(contents), "expected sizeof(contents), got %lu\n", ovl.InternalHigh); ok(!memcmp(contents, buf, sizeof(contents)), "file contents mismatch\n"); - iob.Status = -1; + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + + SetFilePointer(hfile, sizeof(contents) - 4, NULL, FILE_BEGIN); + SetEndOfFile(hfile); + SetFilePointer(hfile, 0, NULL, FILE_BEGIN); + + U(iob).Status = -1; iob.Information = -1; - offset.QuadPart = sizeof(contents) - 4; + offset.QuadPart = (LONGLONG)-1 /* FILE_WRITE_TO_END_OF_FILE */; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, "DCBA", 4, &offset, NULL); - ok(status == STATUS_PENDING || broken(status == STATUS_SUCCESS) /* before Vista */, "expected STATUS_PENDING, got %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); + ok(status == STATUS_PENDING || status == STATUS_SUCCESS /* before Vista */, "expected STATUS_PENDING or STATUS_SUCCESS, got %#x\n", status); + if (status == STATUS_PENDING) + { + ret = WaitForSingleObject(hfile, 3000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + } + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); ok(iob.Information == 4, "expected 4, got %lu\n", iob.Information); - ret = WaitForSingleObject(hfile, 3000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); - iob.Status = -1; + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); - ok(status == STATUS_PENDING, "expected STATUS_PENDING, got %#x\n", status); - ok(iob.Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", iob.Status); + ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "expected STATUS_PENDING or STATUS_SUCCESS, got %#x\n", status); + if (status == STATUS_PENDING) + { + ret = WaitForSingleObject(hfile, 3000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + } + ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status); ok(iob.Information == sizeof(contents), "expected sizeof(contents), got %lu\n", iob.Information); - ret = WaitForSingleObject(hfile, 3000); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + ok(!memcmp(contents, buf, sizeof(contents) - 4), "file contents mismatch\n"); ok(!memcmp(buf + sizeof(contents) - 4, "DCBA", 4), "file contents mismatch\n"); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + S(U(ovl)).Offset = sizeof(contents) - 4; S(U(ovl)).OffsetHigh = 0; ovl.Internal = -1; @@ -2294,12 +2621,19 @@ todo_wine bytes = 0; SetLastError(0xdeadbeef); ret = WriteFile(hfile, "ABCD", 4, &bytes, &ovl); - ok(!ret || broken(ret) /* before Vista */, "WriteFile should fail\n"); - ok(GetLastError() == ERROR_IO_PENDING || broken(GetLastError() == 0xdeadbeef) /* before Vista */, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); - ok(bytes == 0 || broken(bytes == 4) /* before Vista */, "bytes %u\n", bytes); + /* WriteFile return value depends on Windows version and testing it is not practical */ + if (!ret) + { + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + } + else ok(bytes == 4, "bytes %u\n", bytes); ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); ok(ovl.InternalHigh == 4, "expected 4, got %lu\n", ovl.InternalHigh); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + bytes = 0xdeadbeef; ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); ok(ret, "GetOverlappedResult error %d\n", GetLastError()); @@ -2307,6 +2641,9 @@ todo_wine ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); ok(ovl.InternalHigh == 4, "expected 4, got %lu\n", ovl.InternalHigh); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + S(U(ovl)).Offset = 0; S(U(ovl)).OffsetHigh = 0; ovl.Internal = -1; @@ -2315,12 +2652,19 @@ todo_wine bytes = 0; SetLastError(0xdeadbeef); ret = ReadFile(hfile, buf, sizeof(buf), &bytes, &ovl); - ok(!ret, "ReadFile should fail\n"); - ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); - ok(bytes == 0, "bytes %u\n", bytes); + /* ReadFile return value depends on Windows version and testing it is not practical */ + if (!ret) + { + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); + ok(bytes == 0, "bytes %u\n", bytes); + } + else ok(bytes == 14, "bytes %u\n", bytes); ok((NTSTATUS)ovl.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", ovl.Internal); ok(ovl.InternalHigh == sizeof(contents), "expected sizeof(contents), got %lu\n", ovl.InternalHigh); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + bytes = 0xdeadbeef; ret = GetOverlappedResult(hfile, &ovl, &bytes, TRUE); ok(ret, "GetOverlappedResult error %d\n", GetLastError()); @@ -2330,6 +2674,9 @@ todo_wine ok(!memcmp(contents, buf, sizeof(contents) - 4), "file contents mismatch\n"); ok(!memcmp(buf + sizeof(contents) - 4, "ABCD", 4), "file contents mismatch\n"); + off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); + ok(off == 0, "expected 0, got %u\n", off); + CloseHandle(hfile); } diff --git a/rostests/winetests/ntdll/generated.c b/rostests/winetests/ntdll/generated.c index 9e9fc31426f..f8ef346c776 100755 --- a/rostests/winetests/ntdll/generated.c +++ b/rostests/winetests/ntdll/generated.c @@ -1903,13 +1903,6 @@ static void test_pack_PCSTR(void) TEST_TARGET_ALIGN(PCSTR, 1) } -static void test_pack_PCTSTR(void) -{ - /* PCTSTR */ - TEST_TYPE_SIZE (PCTSTR, 8) - TEST_TYPE_ALIGN (PCTSTR, 8) -} - static void test_pack_PCWCH(void) { /* PCWCH */ @@ -2574,13 +2567,6 @@ static void test_pack_PTOKEN_USER(void) TEST_TARGET_ALIGN(PTOKEN_USER, 8) } -static void test_pack_PTSTR(void) -{ - /* PTSTR */ - TEST_TYPE_SIZE (PTSTR, 8) - TEST_TYPE_ALIGN (PTSTR, 8) -} - static void test_pack_PULARGE_INTEGER(void) { /* PULARGE_INTEGER */ @@ -2935,13 +2921,6 @@ static void test_pack_SYSTEM_AUDIT_ACE(void) TEST_FIELD_OFFSET(SYSTEM_AUDIT_ACE, SidStart, 8) } -static void test_pack_TCHAR(void) -{ - /* TCHAR */ - TEST_TYPE_SIZE (TCHAR, 1) - TEST_TYPE_ALIGN (TCHAR, 1) -} - static void test_pack_TOKEN_DEFAULT_DACL(void) { /* TOKEN_DEFAULT_DACL */ @@ -5271,13 +5250,6 @@ static void test_pack_PCSTR(void) TEST_TARGET_ALIGN(PCSTR, 1) } -static void test_pack_PCTSTR(void) -{ - /* PCTSTR */ - TEST_TYPE_SIZE (PCTSTR, 4) - TEST_TYPE_ALIGN (PCTSTR, 4) -} - static void test_pack_PCWCH(void) { /* PCWCH */ @@ -5940,13 +5912,6 @@ static void test_pack_PTOKEN_USER(void) TEST_TARGET_ALIGN(PTOKEN_USER, 4) } -static void test_pack_PTSTR(void) -{ - /* PTSTR */ - TEST_TYPE_SIZE (PTSTR, 4) - TEST_TYPE_ALIGN (PTSTR, 4) -} - static void test_pack_PULARGE_INTEGER(void) { /* PULARGE_INTEGER */ @@ -6301,13 +6266,6 @@ static void test_pack_SYSTEM_AUDIT_ACE(void) TEST_FIELD_OFFSET(SYSTEM_AUDIT_ACE, SidStart, 8) } -static void test_pack_TCHAR(void) -{ - /* TCHAR */ - TEST_TYPE_SIZE (TCHAR, 1) - TEST_TYPE_ALIGN (TCHAR, 1) -} - static void test_pack_TOKEN_DEFAULT_DACL(void) { /* TOKEN_DEFAULT_DACL */ @@ -6935,7 +6893,6 @@ static void test_pack(void) test_pack_PCCH(); test_pack_PCH(); test_pack_PCSTR(); - test_pack_PCTSTR(); test_pack_PCWCH(); test_pack_PCWSTR(); test_pack_PEXCEPTION_POINTERS(); @@ -7022,7 +6979,6 @@ static void test_pack(void) test_pack_PTOKEN_GROUPS(); test_pack_PTOKEN_PRIVILEGES(); test_pack_PTOKEN_USER(); - test_pack_PTSTR(); test_pack_PULARGE_INTEGER(); test_pack_PVECTORED_EXCEPTION_HANDLER(); test_pack_PVOID(); @@ -7052,7 +7008,6 @@ static void test_pack(void) test_pack_SSIZE_T(); test_pack_SYSTEM_ALARM_ACE(); test_pack_SYSTEM_AUDIT_ACE(); - test_pack_TCHAR(); test_pack_TOKEN_DEFAULT_DACL(); test_pack_TOKEN_GROUPS(); test_pack_TOKEN_OWNER(); diff --git a/rostests/winetests/ntdll/info.c b/rostests/winetests/ntdll/info.c index 87f3c9c3340..af0040166f8 100755 --- a/rostests/winetests/ntdll/info.c +++ b/rostests/winetests/ntdll/info.c @@ -55,7 +55,7 @@ static DWORD one_before_last_pid = 0; static BOOL InitFunctionPtrs(void) { /* All needed functions are NT based, so using GetModuleHandle is a good check */ - HMODULE hntdll = GetModuleHandle("ntdll"); + HMODULE hntdll = GetModuleHandleA("ntdll"); if (!hntdll) { win_skip("Not running on NT\n"); @@ -78,7 +78,7 @@ static BOOL InitFunctionPtrs(void) /* not present before XP */ pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll, "NtGetCurrentProcessorNumber"); - pIsWow64Process = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process"); + pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; return TRUE; } @@ -110,7 +110,7 @@ static void test_query_basic(void) ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER /* vista */, "Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER, got %08x\n", status); - /* Use a existing class, correct length, a pointer to a buffer but no ReturnLength pointer */ + /* Use an existing class, correct length, a pointer to a buffer but no ReturnLength pointer */ trace("Check no ReturnLength pointer\n"); status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); @@ -259,7 +259,7 @@ static void test_query_process(void) DWORD last_pid; ULONG ReturnLength; int i = 0, k = 0; - int is_nt = 0; + BOOL is_nt = FALSE; SYSTEM_BASIC_INFORMATION sbi; /* Copy of our winternl.h structure turned into a private one */ @@ -946,14 +946,14 @@ static void test_query_process_debug_port(int argc, char **argv) DWORD_PTR debug_port = 0xdeadbeef; char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; - STARTUPINFO si = { 0 }; + STARTUPINFOA si = { 0 }; NTSTATUS status; BOOL ret; sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee"); si.cb = sizeof(si); - ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); if (!ret) return; @@ -1099,7 +1099,7 @@ static void test_query_process_image_file_name(void) static void test_query_process_debug_object_handle(int argc, char **argv) { char cmdline[MAX_PATH]; - STARTUPINFO si = {0}; + STARTUPINFOA si = {0}; PROCESS_INFORMATION pi; BOOL ret; HANDLE debug_object; @@ -1108,7 +1108,7 @@ static void test_query_process_debug_object_handle(int argc, char **argv) sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee"); si.cb = sizeof(si); - ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed with last error %u\n", GetLastError()); if (!ret) return; @@ -1198,14 +1198,14 @@ static void test_query_process_debug_flags(int argc, char **argv) DWORD debug_flags = 0xdeadbeef; char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; - STARTUPINFO si = { 0 }; + STARTUPINFOA si = { 0 }; NTSTATUS status; BOOL ret; sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee"); si.cb = sizeof(si); - ret = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); if (!ret) return; @@ -1359,12 +1359,17 @@ static void test_mapprotection(void) addr = NULL; status = pNtMapViewOfSection ( h, GetCurrentProcess(), &addr, 0, 0, &offset, &count, ViewShare, 0, PAGE_READWRITE); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + #if defined(__x86_64__) || defined(__i386__) - memset (addr, 0xc3, 1); /* lret ... in both i386 and x86_64 */ + *(unsigned char*)addr = 0xc3; /* lret ... in both i386 and x86_64 */ +#elif defined(__arm__) + *(unsigned long*)addr = 0xe12fff1e; /* bx lr */ +#else + ok(0, "Add a return opcode for your architecture or expect a crash in this test\n"); +#endif trace("trying to execute code in the readwrite only mapped anon file...\n"); f = addr;f(); trace("...done.\n"); -#endif status = pNtQueryVirtualMemory( GetCurrentProcess(), addr, MemoryBasicInformation, &info, sizeof(info), &retlen ); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); @@ -1390,7 +1395,7 @@ static void test_queryvirtualmemory(void) char stackbuf[42]; HMODULE module; - module = GetModuleHandle( "ntdll.dll" ); + module = GetModuleHandleA( "ntdll.dll" ); trace("Check flags of the PE header of NTDLL.DLL at %p\n", module); status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemoryBasicInformation, &mbi, sizeof(MEMORY_BASIC_INFORMATION), &readcount); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); @@ -1402,7 +1407,7 @@ static void test_queryvirtualmemory(void) ok (mbi.Type == MEM_IMAGE, "mbi.Type is 0x%x, expected 0x%x\n", mbi.Type, MEM_IMAGE); trace("Check flags of a function entry in NTDLL.DLL at %p\n", pNtQueryVirtualMemory); - module = GetModuleHandle( "ntdll.dll" ); + module = GetModuleHandleA( "ntdll.dll" ); status = pNtQueryVirtualMemory(NtCurrentProcess(), pNtQueryVirtualMemory, MemoryBasicInformation, &mbi, sizeof(MEMORY_BASIC_INFORMATION), &readcount); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( readcount == sizeof(MEMORY_BASIC_INFORMATION), "Expected to read %d bytes, got %ld\n",(int)sizeof(MEMORY_BASIC_INFORMATION),readcount); @@ -1430,7 +1435,7 @@ static void test_queryvirtualmemory(void) ok (mbi.Protect == PAGE_READWRITE, "mbi.Protect is 0x%x, expected 0x%x\n", mbi.Protect, PAGE_READWRITE); trace("Check flags of read-only data at %p\n", teststring); - module = GetModuleHandle( NULL ); + module = GetModuleHandleA( NULL ); status = pNtQueryVirtualMemory(NtCurrentProcess(), teststring, MemoryBasicInformation, &mbi, sizeof(MEMORY_BASIC_INFORMATION), &readcount); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( readcount == sizeof(MEMORY_BASIC_INFORMATION), "Expected to read %d bytes, got %ld\n",(int)sizeof(MEMORY_BASIC_INFORMATION),readcount); @@ -1475,7 +1480,7 @@ static void test_affinity(void) GetSystemInfo(&si); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); - proc_affinity = (DWORD_PTR)pbi.Reserved2[0]; + proc_affinity = pbi.AffinityMask; ok( proc_affinity == (1 << si.dwNumberOfProcessors) - 1, "Unexpected process affinity\n" ); proc_affinity = 1 << si.dwNumberOfProcessors; status = pNtSetInformationProcess( GetCurrentProcess(), ProcessAffinityMask, &proc_affinity, sizeof(proc_affinity) ); @@ -1534,7 +1539,7 @@ static void test_affinity(void) ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); - proc_affinity = (DWORD_PTR)pbi.Reserved2[0]; + proc_affinity = pbi.AffinityMask; ok( proc_affinity == 2, "Unexpected process affinity\n" ); /* Setting the process affinity changes the thread affinity to match */ status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); @@ -1578,7 +1583,7 @@ static void test_NtGetCurrentProcessorNumber(void) trace("dwNumberOfProcessors: %d, current processor: %d\n", si.dwNumberOfProcessors, current_cpu); status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), NULL); - old_process_mask = (DWORD_PTR)pbi.Reserved2[0]; + old_process_mask = pbi.AffinityMask; ok(status == STATUS_SUCCESS, "got 0x%x (expected STATUS_SUCCESS)\n", status); status = pNtQueryInformationThread(GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL); @@ -1721,7 +1726,7 @@ START_TEST(info) trace("Starting test_process_debug_flags()\n"); test_query_process_debug_flags(argc, argv); - /* belongs into it's own file */ + /* belongs to its own file */ trace("Starting test_readvirtualmemory()\n"); test_readvirtualmemory(); diff --git a/rostests/winetests/ntdll/om.c b/rostests/winetests/ntdll/om.c index a5ffda7cdfb..cca05c90819 100644 --- a/rostests/winetests/ntdll/om.c +++ b/rostests/winetests/ntdll/om.c @@ -26,7 +26,7 @@ #include "stdlib.h" static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*, BOOL, LPCSTR); -static NTSTATUS (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); +static BOOLEAN (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); static VOID (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); static NTSTATUS (WINAPI *pNtCreateEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN, BOOLEAN); diff --git a/rostests/winetests/ntdll/path.c b/rostests/winetests/ntdll/path.c index 29a65833d83..673bc9339b5 100755 --- a/rostests/winetests/ntdll/path.c +++ b/rostests/winetests/ntdll/path.c @@ -30,7 +30,7 @@ static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRI static DWORD (WINAPI *pRtlGetFullPathName_U)(const WCHAR*,ULONG,WCHAR*,WCHAR**); -static void test_RtlDetermineDosPathNameType(void) +static void test_RtlDetermineDosPathNameType_U(void) { struct test { @@ -75,6 +75,12 @@ static void test_RtlDetermineDosPathNameType(void) WCHAR buffer[MAX_PATH]; UINT ret; + if (!pRtlDetermineDosPathNameType_U) + { + win_skip("RtlDetermineDosPathNameType_U is not available\n"); + return; + } + for (test = tests; test->path; test++) { pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 ); @@ -84,7 +90,7 @@ static void test_RtlDetermineDosPathNameType(void) } -static void test_RtlIsDosDeviceName(void) +static void test_RtlIsDosDeviceName_U(void) { struct test { @@ -96,8 +102,8 @@ static void test_RtlIsDosDeviceName(void) static const struct test tests[] = { - { "\\\\.\\CON", 8, 6 }, - { "\\\\.\\con", 8, 6 }, + { "\\\\.\\CON", 8, 6, TRUE }, /* fails on win8 */ + { "\\\\.\\con", 8, 6, TRUE }, /* fails on win8 */ { "\\\\.\\CON2", 0, 0 }, { "", 0, 0 }, { "\\\\foo\\nul", 0, 0 }, @@ -144,6 +150,12 @@ static void test_RtlIsDosDeviceName(void) WCHAR buffer[2000]; ULONG ret; + if (!pRtlIsDosDeviceName_U) + { + win_skip("RtlIsDosDeviceName_U is not available\n"); + return; + } + for (test = tests; test->path; test++) { pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 ); @@ -197,6 +209,12 @@ static void test_RtlIsNameLegalDOS8Dot3(void) char buff2[12]; BOOLEAN ret, spaces; + if (!pRtlIsNameLegalDOS8Dot3) + { + win_skip("RtlIsNameLegalDOS8Dot3 is not available\n"); + return; + } + ustr.MaximumLength = sizeof(buffer); ustr.Buffer = buffer; for (test = tests; test->path; test++) @@ -274,6 +292,12 @@ static void test_RtlGetFullPathName_U(void) DWORD reslen; UINT len; + if (!pRtlGetFullPathName_U) + { + win_skip("RtlGetFullPathName_U is not available\n"); + return; + } + file_part = (WCHAR *)0xdeadbeef; lstrcpyW(rbufferW, deadbeefW); ret = pRtlGetFullPathName_U(NULL, MAX_PATH, rbufferW, &file_part); @@ -336,12 +360,9 @@ START_TEST(path) pRtlOemStringToUnicodeString = (void *)GetProcAddress(mod,"RtlOemStringToUnicodeString"); pRtlIsNameLegalDOS8Dot3 = (void *)GetProcAddress(mod,"RtlIsNameLegalDOS8Dot3"); pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U"); - if (pRtlDetermineDosPathNameType_U) - test_RtlDetermineDosPathNameType(); - if (pRtlIsDosDeviceName_U) - test_RtlIsDosDeviceName(); - if (pRtlIsNameLegalDOS8Dot3) - test_RtlIsNameLegalDOS8Dot3(); - if (pRtlGetFullPathName_U && pRtlMultiByteToUnicodeN) - test_RtlGetFullPathName_U(); + + test_RtlDetermineDosPathNameType_U(); + test_RtlIsDosDeviceName_U(); + test_RtlIsNameLegalDOS8Dot3(); + test_RtlGetFullPathName_U(); } diff --git a/rostests/winetests/ntdll/pipe.c b/rostests/winetests/ntdll/pipe.c index 3ab4d07568d..c275e3d5325 100644 --- a/rostests/winetests/ntdll/pipe.c +++ b/rostests/winetests/ntdll/pipe.c @@ -77,7 +77,7 @@ static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR static BOOL init_func_ptrs(void) { - HMODULE module = GetModuleHandle("ntdll.dll"); + HMODULE module = GetModuleHandleA("ntdll.dll"); #define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \ trace("GetProcAddress(%s) failed\n", #name); \ @@ -91,7 +91,7 @@ static BOOL init_func_ptrs(void) loadfunc(RtlInitUnicodeString) /* not fatal */ - module = GetModuleHandle("kernel32.dll"); + module = GetModuleHandleA("kernel32.dll"); pOpenThread = (void *)GetProcAddress(module, "OpenThread"); pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC"); return TRUE; diff --git a/rostests/winetests/ntdll/port.c b/rostests/winetests/ntdll/port.c index 20e5831b5db..e01316b0cbc 100644 --- a/rostests/winetests/ntdll/port.c +++ b/rostests/winetests/ntdll/port.c @@ -160,7 +160,7 @@ static BOOL init_function_ptrs(void) return FALSE; } - pIsWow64Process = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process"); + pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; return TRUE; } @@ -197,30 +197,30 @@ static void ProcessLpcRequest(HANDLE PortHandle, union lpc_message *LpcMessage) { ok(LpcMessage->msg64.MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType); - ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REQUEST2), + ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST2), "Expected %s, got %s\n", REQUEST2, LpcMessage->msg64.Data); - lstrcpy((LPSTR)LpcMessage->msg64.Data, REPLY); + strcpy((LPSTR)LpcMessage->msg64.Data, REPLY); status = pNtReplyPort(PortHandle, &LpcMessage->msg); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(LpcMessage->msg64.MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->msg64.MessageType); - ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REPLY), + ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REPLY), "Expected %s, got %s\n", REPLY, LpcMessage->msg64.Data); } else { ok(LpcMessage->msg.MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType); - ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REQUEST2), + ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST2), "Expected %s, got %s\n", REQUEST2, LpcMessage->msg.Data); - lstrcpy((LPSTR)LpcMessage->msg.Data, REPLY); + strcpy((LPSTR)LpcMessage->msg.Data, REPLY); status = pNtReplyPort(PortHandle, &LpcMessage->msg); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(LpcMessage->msg.MessageType == LPC_REQUEST, "Expected LPC_REQUEST, got %d\n", LpcMessage->msg.MessageType); - ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REPLY), + ok(!strcmp((LPSTR)LpcMessage->msg.Data, REPLY), "Expected %s, got %s\n", REPLY, LpcMessage->msg.Data); } } @@ -251,26 +251,26 @@ static DWORD WINAPI test_ports_client(LPVOID arg) LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); out = HeapAlloc(GetProcessHeap(), 0, size); - LpcMessage->msg64.DataSize = lstrlen(REQUEST1) + 1; + LpcMessage->msg64.DataSize = strlen(REQUEST1) + 1; LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]); - lstrcpy((LPSTR)LpcMessage->msg64.Data, REQUEST1); + strcpy((LPSTR)LpcMessage->msg64.Data, REQUEST1); status = pNtRequestPort(PortHandle, &LpcMessage->msg); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(LpcMessage->msg64.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg64.MessageType); - ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1), + ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data); /* Fill in the message */ memset(LpcMessage, 0, size); - LpcMessage->msg64.DataSize = lstrlen(REQUEST2) + 1; + LpcMessage->msg64.DataSize = strlen(REQUEST2) + 1; LpcMessage->msg64.MessageSize = FIELD_OFFSET(LPC_MESSAGE64, Data[LpcMessage->msg64.DataSize]); - lstrcpy((LPSTR)LpcMessage->msg64.Data, REQUEST2); + strcpy((LPSTR)LpcMessage->msg64.Data, REQUEST2); /* Send the message and wait for the reply */ status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); - ok(!lstrcmp((LPSTR)out->msg64.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg64.Data); + ok(!strcmp((LPSTR)out->msg64.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg64.Data); ok(out->msg64.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg64.MessageType); } else @@ -279,26 +279,26 @@ static DWORD WINAPI test_ports_client(LPVOID arg) LpcMessage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); out = HeapAlloc(GetProcessHeap(), 0, size); - LpcMessage->msg.DataSize = lstrlen(REQUEST1) + 1; + LpcMessage->msg.DataSize = strlen(REQUEST1) + 1; LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]); - lstrcpy((LPSTR)LpcMessage->msg.Data, REQUEST1); + strcpy((LPSTR)LpcMessage->msg.Data, REQUEST1); status = pNtRequestPort(PortHandle, &LpcMessage->msg); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); ok(LpcMessage->msg.MessageType == 0, "Expected 0, got %d\n", LpcMessage->msg.MessageType); - ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REQUEST1), + ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data); /* Fill in the message */ memset(LpcMessage, 0, size); - LpcMessage->msg.DataSize = lstrlen(REQUEST2) + 1; + LpcMessage->msg.DataSize = strlen(REQUEST2) + 1; LpcMessage->msg.MessageSize = FIELD_OFFSET(LPC_MESSAGE, Data[LpcMessage->msg.DataSize]); - lstrcpy((LPSTR)LpcMessage->msg.Data, REQUEST2); + strcpy((LPSTR)LpcMessage->msg.Data, REQUEST2); /* Send the message and wait for the reply */ status = pNtRequestWaitReplyPort(PortHandle, &LpcMessage->msg, &out->msg); ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %x\n", status); - ok(!lstrcmp((LPSTR)out->msg.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg.Data); + ok(!strcmp((LPSTR)out->msg.Data, REPLY), "Expected %s, got %s\n", REPLY, out->msg.Data); ok(out->msg.MessageType == LPC_REPLY, "Expected LPC_REPLY, got %d\n", out->msg.MessageType); } @@ -345,10 +345,10 @@ static void test_ports_server( HANDLE PortHandle ) case LPC_DATAGRAM: if (is_wow64) - ok(!lstrcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1), + ok(!strcmp((LPSTR)LpcMessage->msg64.Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->msg64.Data); else - ok(!lstrcmp((LPSTR)LpcMessage->msg.Data, REQUEST1), + ok(!strcmp((LPSTR)LpcMessage->msg.Data, REQUEST1), "Expected %s, got %s\n", REQUEST1, LpcMessage->msg.Data); break; diff --git a/rostests/winetests/ntdll/reg.c b/rostests/winetests/ntdll/reg.c index 076948e2baa..159466576eb 100755 --- a/rostests/winetests/ntdll/reg.c +++ b/rostests/winetests/ntdll/reg.c @@ -115,7 +115,7 @@ typedef enum _KEY_VALUE_INFORMATION_CLASS { #endif -static NTSTATUS (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); +static BOOLEAN (WINAPI * pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, LPCSTR); static void (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING,PCWSTR); static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING); static NTSTATUS (WINAPI * pNtDeleteValueKey)(IN HANDLE, IN PUNICODE_STRING); @@ -134,7 +134,7 @@ static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG, ULONG, const void*, ULONG ); static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG); static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING); -static NTSTATUS (WINAPI * pRtlCreateUnicodeString)( PUNICODE_STRING, LPCWSTR); +static BOOLEAN (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR); static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG); static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR); static NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PSTRING, PUNICODE_STRING, BOOL); diff --git a/rostests/winetests/ntdll/rtl.c b/rostests/winetests/ntdll/rtl.c index 38909a31d1f..6eb6de3cb04 100755 --- a/rostests/winetests/ntdll/rtl.c +++ b/rostests/winetests/ntdll/rtl.c @@ -89,6 +89,7 @@ static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,US static CHAR * (WINAPI *pRtlIpv4AddressToStringA)(const IN_ADDR *, LPSTR); static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG); static NTSTATUS (WINAPI *pRtlIpv4StringToAddressA)(PCSTR, BOOLEAN, PCSTR *, IN_ADDR *); +static NTSTATUS (WINAPI *pLdrAddRefDll)(ULONG, HMODULE); static HMODULE hkernel32 = 0; static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); @@ -133,6 +134,7 @@ static void InitFunctionPtrs(void) pRtlIpv4AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringA"); pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA"); pRtlIpv4StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressA"); + pLdrAddRefDll = (void *)GetProcAddress(hntdll, "LdrAddRefDll"); } hkernel32 = LoadLibraryA("kernel32.dll"); ok(hkernel32 != 0, "LoadLibrary failed\n"); @@ -1486,6 +1488,61 @@ static void test_RtlIpv4StringToAddress(void) } } +static void test_LdrAddRefDll(void) +{ + HMODULE mod, mod2; + NTSTATUS status; + BOOL ret; + + if (!pLdrAddRefDll) + { + win_skip( "LdrAddRefDll not supported\n" ); + return; + } + + mod = LoadLibraryA("comctl32.dll"); + ok(mod != NULL, "got %p\n", mod); + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + + mod2 = GetModuleHandleA("comctl32.dll"); + ok(mod2 == NULL, "got %p\n", mod2); + + /* load, addref and release 2 times */ + mod = LoadLibraryA("comctl32.dll"); + ok(mod != NULL, "got %p\n", mod); + status = pLdrAddRefDll(0, mod); + ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + + mod2 = GetModuleHandleA("comctl32.dll"); + ok(mod2 != NULL, "got %p\n", mod2); + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + + mod2 = GetModuleHandleA("comctl32.dll"); + ok(mod2 == NULL, "got %p\n", mod2); + + /* pin refcount */ + mod = LoadLibraryA("comctl32.dll"); + ok(mod != NULL, "got %p\n", mod); + status = pLdrAddRefDll(LDR_ADDREF_DLL_PIN, mod); + ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); + + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + ret = FreeLibrary(mod); + ok(ret, "got %d\n", ret); + + mod2 = GetModuleHandleA("comctl32.dll"); + ok(mod2 != NULL, "got %p\n", mod2); +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -1510,4 +1567,5 @@ START_TEST(rtl) test_RtlIpv4AddressToString(); test_RtlIpv4AddressToStringEx(); test_RtlIpv4StringToAddress(); + test_LdrAddRefDll(); } diff --git a/rostests/winetests/ntdll/rtlstr.c b/rostests/winetests/ntdll/rtlstr.c index 240fe6127f3..dc27c3e6754 100755 --- a/rostests/winetests/ntdll/rtlstr.c +++ b/rostests/winetests/ntdll/rtlstr.c @@ -68,6 +68,8 @@ static NTSTATUS (WINAPI *pRtlGUIDFromString)(const UNICODE_STRING*,GUID*); static NTSTATUS (WINAPI *pRtlStringFromGUID)(const GUID*, UNICODE_STRING*); static BOOLEAN (WINAPI *pRtlIsTextUnicode)(LPVOID, INT, INT *); static NTSTATUS (WINAPI *pRtlHashUnicodeString)(PCUNICODE_STRING,BOOLEAN,ULONG,ULONG*); +static NTSTATUS (WINAPI *pRtlUnicodeToUTF8N)(CHAR *, ULONG, ULONG *, const WCHAR *, ULONG); +static NTSTATUS (WINAPI *pRtlUTF8ToUnicodeN)(WCHAR *, ULONG, ULONG *, const CHAR *, ULONG); /*static VOID (WINAPI *pRtlFreeOemString)(PSTRING);*/ /*static VOID (WINAPI *pRtlCopyUnicodeString)(UNICODE_STRING *, const UNICODE_STRING *);*/ @@ -137,6 +139,8 @@ static void InitFunctionPtrs(void) pRtlStringFromGUID = (void *)GetProcAddress(hntdll, "RtlStringFromGUID"); pRtlIsTextUnicode = (void *)GetProcAddress(hntdll, "RtlIsTextUnicode"); pRtlHashUnicodeString = (void*)GetProcAddress(hntdll, "RtlHashUnicodeString"); + pRtlUnicodeToUTF8N = (void*)GetProcAddress(hntdll, "RtlUnicodeToUTF8N"); + pRtlUTF8ToUnicodeN = (void*)GetProcAddress(hntdll, "RtlUTF8ToUnicodeN"); } } @@ -1971,6 +1975,527 @@ static void test_RtlHashUnicodeString(void) } } +struct unicode_to_utf8_test { + WCHAR unicode[128]; + const char *expected; + NTSTATUS status; +}; + +static const struct unicode_to_utf8_test unicode_to_utf8[] = { + { { 0 }, "", STATUS_SUCCESS }, + { { '-',0 }, "-", STATUS_SUCCESS }, + { { 'h','e','l','l','o',0 }, "hello", STATUS_SUCCESS }, + { { '-',0x7f,'-',0x80,'-',0xff,'-',0x100,'-',0 }, "-\x7F-\xC2\x80-\xC3\xBF-\xC4\x80-", STATUS_SUCCESS }, + { { '-',0x7ff,'-',0x800,'-',0 }, "-\xDF\xBF-\xE0\xA0\x80-", STATUS_SUCCESS }, + { { '-',0xd7ff,'-',0xe000,'-',0 }, "-\xED\x9F\xBF-\xEE\x80\x80-", STATUS_SUCCESS }, + /* 0x10000 */ + { { '-',0xffff,'-',0xd800,0xdc00,'-',0 }, "-\xEF\xBF\xBF-\xF0\x90\x80\x80-", STATUS_SUCCESS }, + /* 0x103ff */ /* 0x10400 */ + { { '-',0xd800,0xdfff,'-',0xd801,0xdc00,'-',0 }, "-\xF0\x90\x8F\xBF-\xF0\x90\x90\x80-", STATUS_SUCCESS }, + /* 0x10ffff */ + { { '-',0xdbff,0xdfff,'-',0 }, "-\xF4\x8F\xBF\xBF-", STATUS_SUCCESS }, + /* standalone lead surrogates become 0xFFFD */ + { { '-',0xd800,'-',0xdbff,'-',0 }, "-\xEF\xBF\xBD-\xEF\xBF\xBD-", STATUS_SOME_NOT_MAPPED }, + /* standalone trail surrogates become 0xFFFD */ + { { '-',0xdc00,'-',0xdfff,'-',0 }, "-\xEF\xBF\xBD-\xEF\xBF\xBD-", STATUS_SOME_NOT_MAPPED }, + /* reverse surrogate pair */ + { { '-',0xdfff,0xdbff,'-',0 }, "-\xEF\xBF\xBD\xEF\xBF\xBD-", STATUS_SOME_NOT_MAPPED }, + /* byte order marks */ + { { '-',0xfeff,'-',0xfffe,'-',0 }, "-\xEF\xBB\xBF-\xEF\xBF\xBE-", STATUS_SUCCESS }, + { { 0xfeff,'-',0 }, "\xEF\xBB\xBF-", STATUS_SUCCESS }, + { { 0xfffe,'-',0 }, "\xEF\xBF\xBE-", STATUS_SUCCESS }, + /* invalid code point */ + { { 0xffff,'-',0 }, "\xEF\xBF\xBF-", STATUS_SUCCESS }, + /* canonically equivalent representations -- no normalization should happen */ + { { '-',0x1e09,'-',0 }, "-\xE1\xB8\x89-", STATUS_SUCCESS }, + { { '-',0x0107,0x0327,'-',0 }, "-\xC4\x87\xCC\xA7-", STATUS_SUCCESS }, + { { '-',0x00e7,0x0301,'-',0 }, "-\xC3\xA7\xCC\x81-", STATUS_SUCCESS }, + { { '-',0x0063,0x0327,0x0301,'-',0 }, "-\x63\xCC\xA7\xCC\x81-", STATUS_SUCCESS }, + { { '-',0x0063,0x0301,0x0327,'-',0 }, "-\x63\xCC\x81\xCC\xA7-", STATUS_SUCCESS }, +}; + +static void utf8_expect_(const unsigned char *out_string, ULONG buflen, ULONG out_bytes, + const WCHAR *in_string, ULONG in_bytes, + NTSTATUS expect_status, int line) +{ + NTSTATUS status; + ULONG bytes_out; + char buffer[128]; + unsigned char *buf = (unsigned char *)buffer; + unsigned int i; + + if (buflen == (ULONG)-1) + buflen = sizeof(buffer); + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUnicodeToUTF8N( + out_string ? buffer : NULL, buflen, &bytes_out, + in_string, in_bytes); + ok_(__FILE__, line)(status == expect_status, "status = 0x%x\n", status); + ok_(__FILE__, line)(bytes_out == out_bytes, "bytes_out = %u\n", bytes_out); + if (out_string) + { + for (i = 0; i < bytes_out; i++) + ok_(__FILE__, line)(buf[i] == out_string[i], + "buffer[%d] = 0x%x, expected 0x%x\n", + i, buf[i], out_string[i]); + for (; i < sizeof(buffer); i++) + ok_(__FILE__, line)(buf[i] == 0x55, + "buffer[%d] = 0x%x, expected 0x55\n", + i, buf[i]); + } +} +#define utf8_expect(out_string, buflen, out_bytes, in_string, in_bytes, expect_status) \ + utf8_expect_(out_string, buflen, out_bytes, in_string, in_bytes, expect_status, __LINE__) + +static void test_RtlUnicodeToUTF8N(void) +{ + NTSTATUS status; + ULONG bytes_out; + ULONG bytes_out_array[2]; + void * const invalid_pointer = (void *)0x8; + char buffer[128]; + const WCHAR empty_string[] = { 0 }; + const WCHAR test_string[] = { 'A',0,'a','b','c','d','e','f','g',0 }; + const WCHAR special_string[] = { 'X',0x80,0xd800,0 }; + const unsigned char special_expected[] = { 'X',0xc2,0x80,0xef,0xbf,0xbd,0 }; + unsigned int input_len; + const unsigned int test_count = sizeof(unicode_to_utf8) / sizeof(unicode_to_utf8[0]); + unsigned int i; + + if (!pRtlUnicodeToUTF8N) + { + skip("RtlUnicodeToUTF8N unavailable\n"); + return; + } + + /* show that bytes_out is really ULONG */ + memset(bytes_out_array, 0x55, sizeof(bytes_out_array)); + status = pRtlUnicodeToUTF8N(NULL, 0, bytes_out_array, empty_string, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out_array[0] == 0x00000000, "Got 0x%x\n", bytes_out_array[0]); + ok(bytes_out_array[1] == 0x55555555, "Got 0x%x\n", bytes_out_array[1]); + + /* parameter checks */ + status = pRtlUnicodeToUTF8N(NULL, 0, NULL, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER_4, "status = 0x%x\n", status); + + status = pRtlUnicodeToUTF8N(NULL, 0, NULL, empty_string, 0); + ok(status == STATUS_INVALID_PARAMETER, "status = 0x%x\n", status); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(NULL, 0, &bytes_out, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER_4, "status = 0x%x\n", status); + ok(bytes_out == 0x55555555, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(NULL, 0, &bytes_out, invalid_pointer, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(NULL, 0, &bytes_out, empty_string, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(NULL, 0, &bytes_out, test_string, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(NULL, 0, &bytes_out, empty_string, 1); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(invalid_pointer, 0, &bytes_out, empty_string, 1); + ok(status == STATUS_INVALID_PARAMETER_5, "status = 0x%x\n", status); + ok(bytes_out == 0x55555555, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUnicodeToUTF8N(invalid_pointer, 8, &bytes_out, empty_string, 1); + ok(status == STATUS_INVALID_PARAMETER_5, "status = 0x%x\n", status); + ok(bytes_out == 0x55555555, "bytes_out = 0x%x\n", bytes_out); + + /* length output with special chars */ +#define length_expect(in_chars, out_bytes, expect_status) \ + utf8_expect_(NULL, 0, out_bytes, \ + special_string, in_chars * sizeof(WCHAR), \ + expect_status, __LINE__) + + length_expect(0, 0, STATUS_SUCCESS); + length_expect(1, 1, STATUS_SUCCESS); + length_expect(2, 3, STATUS_SUCCESS); + length_expect(3, 6, STATUS_SOME_NOT_MAPPED); + length_expect(4, 7, STATUS_SOME_NOT_MAPPED); +#undef length_expect + + /* output truncation */ +#define truncate_expect(buflen, out_bytes, expect_status) \ + utf8_expect_(special_expected, buflen, out_bytes, \ + special_string, sizeof(special_string), \ + expect_status, __LINE__) + + truncate_expect(0, 0, STATUS_BUFFER_TOO_SMALL); + truncate_expect(1, 1, STATUS_BUFFER_TOO_SMALL); + truncate_expect(2, 1, STATUS_BUFFER_TOO_SMALL); + truncate_expect(3, 3, STATUS_BUFFER_TOO_SMALL); + truncate_expect(4, 3, STATUS_BUFFER_TOO_SMALL); + truncate_expect(5, 3, STATUS_BUFFER_TOO_SMALL); + truncate_expect(6, 6, STATUS_BUFFER_TOO_SMALL); + truncate_expect(7, 7, STATUS_SOME_NOT_MAPPED); +#undef truncate_expect + + /* conversion behavior with varying input length */ + for (input_len = 0; input_len <= sizeof(test_string); input_len++) { + /* no output buffer, just length */ + utf8_expect(NULL, 0, input_len / sizeof(WCHAR), + test_string, input_len, STATUS_SUCCESS); + + /* write output */ + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUnicodeToUTF8N( + buffer, sizeof(buffer), &bytes_out, + test_string, input_len); + if (input_len % sizeof(WCHAR) == 0) { + ok(status == STATUS_SUCCESS, + "(len %u): status = 0x%x\n", input_len, status); + ok(bytes_out == input_len / sizeof(WCHAR), + "(len %u): bytes_out = 0x%x\n", input_len, bytes_out); + for (i = 0; i < bytes_out; i++) { + ok(buffer[i] == test_string[i], + "(len %u): buffer[%d] = 0x%x, expected 0x%x\n", + input_len, i, buffer[i], test_string[i]); + } + for (; i < sizeof(buffer); i++) { + ok(buffer[i] == 0x55, + "(len %u): buffer[%d] = 0x%x\n", input_len, i, buffer[i]); + } + } else { + ok(status == STATUS_INVALID_PARAMETER_5, + "(len %u): status = 0x%x\n", input_len, status); + ok(bytes_out == 0x55555555, + "(len %u): bytes_out = 0x%x\n", input_len, bytes_out); + for (i = 0; i < sizeof(buffer); i++) { + ok(buffer[i] == 0x55, + "(len %u): buffer[%d] = 0x%x\n", input_len, i, buffer[i]); + } + } + } + + /* test cases for special characters */ + for (i = 0; i < test_count; i++) { + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUnicodeToUTF8N( + buffer, sizeof(buffer), &bytes_out, + unicode_to_utf8[i].unicode, lstrlenW(unicode_to_utf8[i].unicode) * sizeof(WCHAR)); + ok(status == unicode_to_utf8[i].status, + "(test %d): status is 0x%x, expected 0x%x\n", + i, status, unicode_to_utf8[i].status); + ok(bytes_out == strlen(unicode_to_utf8[i].expected), + "(test %d): bytes_out is %u, expected %u\n", + i, bytes_out, lstrlenA(unicode_to_utf8[i].expected)); + ok(!memcmp(buffer, unicode_to_utf8[i].expected, bytes_out), + "(test %d): got \"%.*s\", expected \"%s\"\n", + i, bytes_out, buffer, unicode_to_utf8[i].expected); + ok(buffer[bytes_out] == 0x55, + "(test %d): behind string: 0x%x\n", i, buffer[bytes_out]); + + /* same test but include the null terminator */ + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUnicodeToUTF8N( + buffer, sizeof(buffer), &bytes_out, + unicode_to_utf8[i].unicode, (lstrlenW(unicode_to_utf8[i].unicode) + 1) * sizeof(WCHAR)); + ok(status == unicode_to_utf8[i].status, + "(test %d): status is 0x%x, expected 0x%x\n", + i, status, unicode_to_utf8[i].status); + ok(bytes_out == strlen(unicode_to_utf8[i].expected) + 1, + "(test %d): bytes_out is %u, expected %u\n", + i, bytes_out, lstrlenA(unicode_to_utf8[i].expected) + 1); + ok(!memcmp(buffer, unicode_to_utf8[i].expected, bytes_out), + "(test %d): got \"%.*s\", expected \"%s\"\n", + i, bytes_out, buffer, unicode_to_utf8[i].expected); + ok(buffer[bytes_out] == 0x55, + "(test %d): behind string: 0x%x\n", i, buffer[bytes_out]); + } +} + +struct utf8_to_unicode_test { + const char *utf8; + WCHAR expected[128]; + NTSTATUS status; +}; + +static const struct utf8_to_unicode_test utf8_to_unicode[] = { + { "", { 0 }, STATUS_SUCCESS }, + { "-", { '-',0 }, STATUS_SUCCESS }, + { "hello", { 'h','e','l','l','o',0 }, STATUS_SUCCESS }, + /* first and last of each range */ + { "-\x7F-\xC2\x80-\xC3\xBF-\xC4\x80-", { '-',0x7f,'-',0x80,'-',0xff,'-',0x100,'-',0 }, STATUS_SUCCESS }, + { "-\xDF\xBF-\xE0\xA0\x80-", { '-',0x7ff,'-',0x800,'-',0 }, STATUS_SUCCESS }, + { "-\xED\x9F\xBF-\xEE\x80\x80-", { '-',0xd7ff,'-',0xe000,'-',0 }, STATUS_SUCCESS }, + /* 0x10000 */ + { "-\xEF\xBF\xBF-\xF0\x90\x80\x80-", { '-',0xffff,'-',0xd800,0xdc00,'-',0 }, STATUS_SUCCESS }, + /* 0x103ff */ /* 0x10400 */ + { "-\xF0\x90\x8F\xBF-\xF0\x90\x90\x80-", { '-',0xd800,0xdfff,'-',0xd801,0xdc00,'-',0 }, STATUS_SUCCESS }, + /* 0x10ffff */ + { "-\xF4\x8F\xBF\xBF-", { '-',0xdbff,0xdfff,'-',0 }, STATUS_SUCCESS }, + /* standalone surrogate code points */ + /* 0xd800 */ /* 0xdbff */ + { "-\xED\xA0\x80-\xED\xAF\xBF-", { '-',0xfffd,0xfffd,'-',0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* 0xdc00 */ /* 0xdfff */ + { "-\xED\xB0\x80-\xED\xBF\xBF-", { '-',0xfffd,0xfffd,'-',0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* UTF-8 encoded surrogate pair */ + /* 0xdbff *//* 0xdfff */ + { "-\xED\xAF\xBF\xED\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* reverse surrogate pair */ + /* 0xdfff *//* 0xdbff */ + { "-\xED\xBF\xBF\xED\xAF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* code points outside the UTF-16 range */ + /* 0x110000 */ + { "-\xF4\x90\x80\x80-", { '-',0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* 0x1fffff */ + { "-\xF7\xBF\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* 0x200000 */ + { "-\xFA\x80\x80\x80\x80-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* 0x3ffffff */ + { "-\xFB\xBF\xBF\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* 0x4000000 */ + { "-\xFC\x84\x80\x80\x80\x80-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* 0x7fffffff */ + { "-\xFD\xBF\xBF\xBF\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* overlong encodings of each length for -, NUL, and the highest possible value */ + { "-\xC0\xAD-\xC0\x80-\xC1\xBF-", { '-',0xfffd,0xfffd,'-',0xfffd,0xfffd,'-',0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xE0\x80\xAD-\xE0\x80\x80-\xE0\x9F\xBF-", { '-',0xfffd,0xfffd,'-',0xfffd,0xfffd,'-',0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xF0\x80\x80\xAD-", { '-',0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xF0\x80\x80\x80-", { '-',0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xF0\x8F\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xF8\x80\x80\x80\xAD-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xF8\x80\x80\x80\x80-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xF8\x87\xBF\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xFC\x80\x80\x80\x80\xAD-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xFC\x80\x80\x80\x80\x80-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "-\xFC\x83\xBF\xBF\xBF\xBF-", { '-',0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* invalid bytes */ + { "\xFE", { 0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFF", { 0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFE\xBF\xBF\xBF\xBF\xBF\xBF\xBF\xBF", { 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFF\xBF\xBF\xBF\xBF\xBF\xBF\xBF\xBF", { 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFF\x80\x80\x80\x80\x80\x80\x80\x80", { 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFF\x40\x80\x80\x80\x80\x80\x80\x80", { 0xfffd,0x40,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + /* lone continuation bytes */ + { "\x80", { 0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\x80\x80", { 0xfffd,0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xBF", { 0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + { "\xBF\xBF", { 0xfffd,0xfffd,0 }, STATUS_SOME_NOT_MAPPED }, + /* incomplete sequences */ + { "\xC2-", { 0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "\xE0\xA0-", { 0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "\xF0\x90\x80-", { 0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "\xF4\x8F\xBF-", { 0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFA\x80\x80\x80-", { 0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + { "\xFC\x84\x80\x80\x80-", { 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* multibyte sequence followed by lone continuation byte */ + { "\xE0\xA0\x80\x80-", { 0x800,0xfffd,'-',0 }, STATUS_SOME_NOT_MAPPED }, + /* byte order marks */ + { "-\xEF\xBB\xBF-\xEF\xBF\xBE-", { '-',0xfeff,'-',0xfffe,'-',0 }, STATUS_SUCCESS }, + { "\xEF\xBB\xBF-", { 0xfeff,'-',0 }, STATUS_SUCCESS }, + { "\xEF\xBF\xBE-", { 0xfffe,'-',0 }, STATUS_SUCCESS }, + /* invalid code point */ + /* 0xffff */ + { "\xEF\xBF\xBF-", { 0xffff,'-',0 }, STATUS_SUCCESS }, + /* canonically equivalent representations -- no normalization should happen */ + { "-\xE1\xB8\x89-", { '-',0x1e09,'-',0 }, STATUS_SUCCESS }, + { "-\xC4\x87\xCC\xA7-", { '-',0x0107,0x0327,'-',0 }, STATUS_SUCCESS }, + { "-\xC3\xA7\xCC\x81-", { '-',0x00e7,0x0301,'-',0 }, STATUS_SUCCESS }, + { "-\x63\xCC\xA7\xCC\x81-", { '-',0x0063,0x0327,0x0301,'-',0 }, STATUS_SUCCESS }, + { "-\x63\xCC\x81\xCC\xA7-", { '-',0x0063,0x0301,0x0327,'-',0 }, STATUS_SUCCESS }, +}; + +static void unicode_expect_(const WCHAR *out_string, ULONG buflen, ULONG out_chars, + const char *in_string, ULONG in_chars, + NTSTATUS expect_status, int line) +{ + NTSTATUS status; + ULONG bytes_out; + WCHAR buffer[128]; + unsigned int i; + + if (buflen == (ULONG)-1) + buflen = sizeof(buffer); + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUTF8ToUnicodeN( + out_string ? buffer : NULL, buflen, &bytes_out, + in_string, in_chars); + ok_(__FILE__, line)(status == expect_status, "status = 0x%x\n", status); + ok_(__FILE__, line)(bytes_out == out_chars * sizeof(WCHAR), + "bytes_out = %u, expected %u\n", bytes_out, out_chars * (ULONG)sizeof(WCHAR)); + if (out_string) + { + for (i = 0; i < bytes_out / sizeof(WCHAR); i++) + ok_(__FILE__, line)(buffer[i] == out_string[i], + "buffer[%d] = 0x%x, expected 0x%x\n", + i, buffer[i], out_string[i]); + for (; i < sizeof(buffer) / sizeof(WCHAR); i++) + ok_(__FILE__, line)(buffer[i] == 0x5555, + "buffer[%d] = 0x%x, expected 0x5555\n", + i, buffer[i]); + } +} +#define unicode_expect(out_string, buflen, out_chars, in_string, in_chars, expect_status) \ + unicode_expect_(out_string, buflen, out_chars, in_string, in_chars, expect_status, __LINE__) + +static void test_RtlUTF8ToUnicodeN(void) +{ + NTSTATUS status; + ULONG bytes_out; + ULONG bytes_out_array[2]; + void * const invalid_pointer = (void *)0x8; + WCHAR buffer[128]; + const char empty_string[] = ""; + const char test_string[] = "A\0abcdefg"; + const WCHAR test_stringW[] = {'A',0,'a','b','c','d','e','f','g',0 }; + const char special_string[] = { 'X',0xc2,0x80,0xF0,0x90,0x80,0x80,0 }; + const WCHAR special_expected[] = { 'X',0x80,0xd800,0xdc00,0 }; + unsigned int input_len; + const unsigned int test_count = sizeof(utf8_to_unicode) / sizeof(utf8_to_unicode[0]); + unsigned int i; + + if (!pRtlUTF8ToUnicodeN) + { + skip("RtlUTF8ToUnicodeN unavailable\n"); + return; + } + + /* show that bytes_out is really ULONG */ + memset(bytes_out_array, 0x55, sizeof(bytes_out_array)); + status = pRtlUTF8ToUnicodeN(NULL, 0, bytes_out_array, empty_string, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out_array[0] == 0x00000000, "Got 0x%x\n", bytes_out_array[0]); + ok(bytes_out_array[1] == 0x55555555, "Got 0x%x\n", bytes_out_array[1]); + + /* parameter checks */ + status = pRtlUTF8ToUnicodeN(NULL, 0, NULL, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER_4, "status = 0x%x\n", status); + + status = pRtlUTF8ToUnicodeN(NULL, 0, NULL, empty_string, 0); + ok(status == STATUS_INVALID_PARAMETER, "status = 0x%x\n", status); + + bytes_out = 0x55555555; + status = pRtlUTF8ToUnicodeN(NULL, 0, &bytes_out, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER_4, "status = 0x%x\n", status); + ok(bytes_out == 0x55555555, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUTF8ToUnicodeN(NULL, 0, &bytes_out, invalid_pointer, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUTF8ToUnicodeN(NULL, 0, &bytes_out, empty_string, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUTF8ToUnicodeN(NULL, 0, &bytes_out, test_string, 0); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == 0, "bytes_out = 0x%x\n", bytes_out); + + bytes_out = 0x55555555; + status = pRtlUTF8ToUnicodeN(NULL, 0, &bytes_out, empty_string, 1); + ok(status == STATUS_SUCCESS, "status = 0x%x\n", status); + ok(bytes_out == sizeof(WCHAR), "bytes_out = 0x%x\n", bytes_out); + + /* length output with special chars */ +#define length_expect(in_chars, out_chars, expect_status) \ + unicode_expect_(NULL, 0, out_chars, special_string, in_chars, \ + expect_status, __LINE__) + + length_expect(0, 0, STATUS_SUCCESS); + length_expect(1, 1, STATUS_SUCCESS); + length_expect(2, 2, STATUS_SOME_NOT_MAPPED); + length_expect(3, 2, STATUS_SUCCESS); + length_expect(4, 3, STATUS_SOME_NOT_MAPPED); + length_expect(5, 3, STATUS_SOME_NOT_MAPPED); + length_expect(6, 3, STATUS_SOME_NOT_MAPPED); + length_expect(7, 4, STATUS_SUCCESS); + length_expect(8, 5, STATUS_SUCCESS); +#undef length_expect + + /* output truncation */ +#define truncate_expect(buflen, out_chars, expect_status) \ + unicode_expect_(special_expected, buflen, out_chars, \ + special_string, sizeof(special_string), \ + expect_status, __LINE__) + + truncate_expect( 0, 0, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 1, 0, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 2, 1, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 3, 1, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 4, 2, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 5, 2, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 6, 3, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 7, 3, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 8, 4, STATUS_BUFFER_TOO_SMALL); + truncate_expect( 9, 4, STATUS_BUFFER_TOO_SMALL); + truncate_expect(10, 5, STATUS_SUCCESS); +#undef truncate_expect + + /* conversion behavior with varying input length */ + for (input_len = 0; input_len <= sizeof(test_string); input_len++) { + /* no output buffer, just length */ + unicode_expect(NULL, 0, input_len, + test_string, input_len, STATUS_SUCCESS); + + /* write output */ + unicode_expect(test_stringW, -1, input_len, + test_string, input_len, STATUS_SUCCESS); + } + + /* test cases for special characters */ + for (i = 0; i < test_count; i++) { + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUTF8ToUnicodeN( + buffer, sizeof(buffer), &bytes_out, + utf8_to_unicode[i].utf8, strlen(utf8_to_unicode[i].utf8)); + ok(status == utf8_to_unicode[i].status, + "(test %d): status is 0x%x, expected 0x%x\n", + i, status, utf8_to_unicode[i].status); + ok(bytes_out == lstrlenW(utf8_to_unicode[i].expected) * sizeof(WCHAR), + "(test %d): bytes_out is %u, expected %u\n", + i, bytes_out, lstrlenW(utf8_to_unicode[i].expected) * (ULONG)sizeof(WCHAR)); + ok(!memcmp(buffer, utf8_to_unicode[i].expected, bytes_out), + "(test %d): got %s, expected %s\n", + i, wine_dbgstr_wn(buffer, bytes_out / sizeof(WCHAR)), wine_dbgstr_w(utf8_to_unicode[i].expected)); + ok(buffer[bytes_out] == 0x5555, + "(test %d): behind string: 0x%x\n", i, buffer[bytes_out]); + + /* same test but include the null terminator */ + bytes_out = 0x55555555; + memset(buffer, 0x55, sizeof(buffer)); + status = pRtlUTF8ToUnicodeN( + buffer, sizeof(buffer), &bytes_out, + utf8_to_unicode[i].utf8, strlen(utf8_to_unicode[i].utf8) + 1); + ok(status == utf8_to_unicode[i].status, + "(test %d): status is 0x%x, expected 0x%x\n", + i, status, utf8_to_unicode[i].status); + ok(bytes_out == (lstrlenW(utf8_to_unicode[i].expected) + 1) * sizeof(WCHAR), + "(test %d): bytes_out is %u, expected %u\n", + i, bytes_out, (lstrlenW(utf8_to_unicode[i].expected) + 1) * (ULONG)sizeof(WCHAR)); + ok(!memcmp(buffer, utf8_to_unicode[i].expected, bytes_out), + "(test %d): got %s, expected %s\n", + i, wine_dbgstr_wn(buffer, bytes_out / sizeof(WCHAR)), wine_dbgstr_w(utf8_to_unicode[i].expected)); + ok(buffer[bytes_out] == 0x5555, + "(test %d): behind string: 0x%x\n", i, buffer[bytes_out]); + } +} + START_TEST(rtlstr) { InitFunctionPtrs(); @@ -2004,4 +2529,6 @@ START_TEST(rtlstr) test_RtlDowncaseUnicodeString(); } test_RtlHashUnicodeString(); + test_RtlUnicodeToUTF8N(); + test_RtlUTF8ToUnicodeN(); } diff --git a/rostests/winetests/ntdll/string.c b/rostests/winetests/ntdll/string.c index 9349f5d7473..56b75849747 100755 --- a/rostests/winetests/ntdll/string.c +++ b/rostests/winetests/ntdll/string.c @@ -59,6 +59,7 @@ static LPWSTR (WINAPIV *p_wcsrchr)(LPCWSTR, WCHAR); static void (__cdecl *p_qsort)(void *,size_t,size_t, int(__cdecl *compar)(const void *, const void *) ); static void* (__cdecl *p_bsearch)(void *,void*,size_t,size_t, int(__cdecl *compar)(const void *, const void *) ); +static int (__cdecl *p__snprintf)(char *, size_t, const char *, ...); static void InitFunctionPtrs(void) @@ -96,6 +97,8 @@ static void InitFunctionPtrs(void) p_wcsrchr= (void *)GetProcAddress(hntdll, "wcsrchr"); p_qsort= (void *)GetProcAddress(hntdll, "qsort"); p_bsearch= (void *)GetProcAddress(hntdll, "bsearch"); + + p__snprintf = (void *)GetProcAddress(hntdll, "_snprintf"); } /* if */ } @@ -1270,6 +1273,37 @@ static void test_bsearch(void) } } +static void test__snprintf(void) +{ + const char *origstring = "XXXXXXXXXXXX"; + const char *teststring = "hello world"; + char buffer[32]; + int res; + + res = p__snprintf(NULL, 0, teststring); + ok(res == lstrlenA(teststring) || broken(res == -1) /* <= w2k */, + "_snprintf returned %d, expected %d.\n", res, lstrlenA(teststring)); + + if (res != -1) + { + res = p__snprintf(NULL, 1, teststring); + ok(res == lstrlenA(teststring) /* WinXP */ || res < 0 /* Vista and greater */, + "_snprintf returned %d, expected %d or < 0.\n", res, lstrlenA(teststring)); + } + res = p__snprintf(buffer, strlen(teststring) - 1, teststring); + ok(res < 0, "_snprintf returned %d, expected < 0.\n", res); + + strcpy(buffer, origstring); + res = p__snprintf(buffer, strlen(teststring), teststring); + ok(res == lstrlenA(teststring), "_snprintf returned %d, expected %d.\n", res, lstrlenA(teststring)); + ok(!strcmp(buffer, "hello worldX"), "_snprintf returned buffer '%s', expected 'hello worldX'.\n", buffer); + + strcpy(buffer, origstring); + res = p__snprintf(buffer, strlen(teststring) + 1, teststring); + ok(res == lstrlenA(teststring), "_snprintf returned %d, expected %d.\n", res, lstrlenA(teststring)); + ok(!strcmp(buffer, teststring), "_snprintf returned buffer '%s', expected '%s'.\n", buffer, teststring); +} + START_TEST(string) { InitFunctionPtrs(); @@ -1304,4 +1338,6 @@ START_TEST(string) test_qsort(); if (p_bsearch) test_bsearch(); + if (p__snprintf) + test__snprintf(); } diff --git a/rostests/winetests/ntdll/testlist.c b/rostests/winetests/ntdll/testlist.c index f9560629ba9..ec81eed5b62 100644 --- a/rostests/winetests/ntdll/testlist.c +++ b/rostests/winetests/ntdll/testlist.c @@ -1,10 +1,7 @@ /* Automatically generated file; DO NOT EDIT!! */ -#define WIN32_LEAN_AND_MEAN -#include - #define STANDALONE -#include "wine/test.h" +#include extern void func_atom(void); extern void func_change(void); diff --git a/rostests/winetests/ntdll/time.c b/rostests/winetests/ntdll/time.c index ff80b841078..48f4640ebb8 100755 --- a/rostests/winetests/ntdll/time.c +++ b/rostests/winetests/ntdll/time.c @@ -33,9 +33,9 @@ static const int MonthLengths[2][12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; -static inline int IsLeapYear(int Year) +static inline BOOL IsLeapYear(int Year) { - return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0; + return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0); } /* start time of the tests */