From 4aec35aa7b5f286e3260038823c968c7974c27fb Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Mon, 3 Oct 2011 19:29:29 +0000 Subject: [PATCH] [NTDLL_WINETEST] * Sync with Wine 1.3.29. svn path=/trunk/; revision=53975 --- rostests/winetests/ntdll/CMakeLists.txt | 3 +- rostests/winetests/ntdll/atom.c | 2 +- rostests/winetests/ntdll/change.c | 12 +- rostests/winetests/ntdll/directory.c | 116 ++++--- rostests/winetests/ntdll/env.c | 1 + rostests/winetests/ntdll/error.c | 61 +++- rostests/winetests/ntdll/exception.c | 163 ++++++--- rostests/winetests/ntdll/file.c | 270 ++++++++++++++- rostests/winetests/ntdll/info.c | 346 ++++++++++++++++++- rostests/winetests/ntdll/large_int.c | 2 +- rostests/winetests/ntdll/ntdll.rbuild | 1 + rostests/winetests/ntdll/om.c | 91 ++++- rostests/winetests/ntdll/pipe.c | 430 ++++++++++++++++++++++++ rostests/winetests/ntdll/port.c | 2 - rostests/winetests/ntdll/reg.c | 6 + rostests/winetests/ntdll/rtl.c | 226 ++++++++++++- rostests/winetests/ntdll/rtlbitmap.c | 6 + rostests/winetests/ntdll/rtlstr.c | 15 +- rostests/winetests/ntdll/string.c | 81 ++++- rostests/winetests/ntdll/testlist.c | 2 + rostests/winetests/ntdll/time.c | 2 +- 21 files changed, 1687 insertions(+), 151 deletions(-) create mode 100644 rostests/winetests/ntdll/pipe.c diff --git a/rostests/winetests/ntdll/CMakeLists.txt b/rostests/winetests/ntdll/CMakeLists.txt index 0fe16a31a38..8bdd5ca5e6e 100644 --- a/rostests/winetests/ntdll/CMakeLists.txt +++ b/rostests/winetests/ntdll/CMakeLists.txt @@ -16,10 +16,11 @@ list(APPEND SOURCE large_int.c om.c path.c + pipe.c port.c reg.c - rtlbitmap.c rtl.c + rtlbitmap.c rtlstr.c string.c time.c diff --git a/rostests/winetests/ntdll/atom.c b/rostests/winetests/ntdll/atom.c index 149078f34bf..0f185657cfe 100755 --- a/rostests/winetests/ntdll/atom.c +++ b/rostests/winetests/ntdll/atom.c @@ -110,7 +110,7 @@ static DWORD WINAPI RtlAtomTestThread(LPVOID Table) Len = 64; res = pRtlQueryAtomInAtomTable(AtomTable, Atom, &RefCount, &PinCount, Name, &Len); - ok(!res, "Failed with longenough buffer, retval: %x\n", res); + ok(!res, "Failed with long enough buffer, retval: %x\n", res); ok(RefCount == 1, "Refcount was not 1 but %x\n", RefCount); ok(PinCount == 1, "Pincount was not 1 but %x\n", PinCount); ok(!lstrcmpW(Name, testAtom2), "We found wrong atom!!\n"); diff --git a/rostests/winetests/ntdll/change.c b/rostests/winetests/ntdll/change.c index ed7f22c9e61..297af9ec11f 100644 --- a/rostests/winetests/ntdll/change.c +++ b/rostests/winetests/ntdll/change.c @@ -27,13 +27,11 @@ #include #include "wine/test.h" -typedef NTSTATUS (WINAPI *fnNtNotifyChangeDirectoryFile)( +static NTSTATUS (WINAPI *pNtNotifyChangeDirectoryFile)( HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID, PIO_STATUS_BLOCK,PVOID,ULONG,ULONG,BOOLEAN); -fnNtNotifyChangeDirectoryFile pNtNotifyChangeDirectoryFile; -typedef NTSTATUS (WINAPI *fnNtCancelIoFile)(HANDLE,PIO_STATUS_BLOCK); -fnNtCancelIoFile pNtCancelIoFile; +static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE,PIO_STATUS_BLOCK); static void test_ntncdf(void) @@ -321,10 +319,8 @@ START_TEST(change) return; } - pNtNotifyChangeDirectoryFile = (fnNtNotifyChangeDirectoryFile) - GetProcAddress(hntdll, "NtNotifyChangeDirectoryFile"); - pNtCancelIoFile = (fnNtCancelIoFile) - GetProcAddress(hntdll, "NtCancelIoFile"); + pNtNotifyChangeDirectoryFile = (void *)GetProcAddress(hntdll, "NtNotifyChangeDirectoryFile"); + pNtCancelIoFile = (void *)GetProcAddress(hntdll, "NtCancelIoFile"); if (!pNtNotifyChangeDirectoryFile || !pNtCancelIoFile) { diff --git a/rostests/winetests/ntdll/directory.c b/rostests/winetests/ntdll/directory.c index a77a4b45326..c74bf341a21 100644 --- a/rostests/winetests/ntdll/directory.c +++ b/rostests/winetests/ntdll/directory.c @@ -50,8 +50,9 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirection)( BOOLEAN enable ); static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG *old_value ); /* The attribute sets to test */ -struct testfile_s { - int todo; /* set if it doesn't work on wine yet */ +static struct testfile_s { + BOOL todo; /* set if it doesn't work on wine yet */ + BOOL attr_done; /* set if attributes were tested for this file already */ const DWORD attr; /* desired attribute */ const char *name; /* filename to use */ const char *target; /* what to point to (only for reparse pts) */ @@ -59,11 +60,13 @@ struct testfile_s { int nfound; /* How many were found (expect 1) */ WCHAR nameW[20]; /* unicode version of name (filled in later) */ } testfiles[] = { - { 0, FILE_ATTRIBUTE_NORMAL, "n.tmp", NULL, "normal" }, - { 1, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" }, - { 1, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" }, - { 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" }, - { 0, 0, NULL } + { 0, 0, FILE_ATTRIBUTE_NORMAL, "n.tmp", NULL, "normal" }, + { 1, 0, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" }, + { 1, 0, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" }, + { 0, 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" }, + { 0, 0, FILE_ATTRIBUTE_DIRECTORY, ".", NULL, ". directory" }, + { 0, 0, FILE_ATTRIBUTE_DIRECTORY, "..", NULL, ".. directory" }, + { 0, 0, 0, NULL } }; static const int max_test_dir_size = 20; /* size of above plus some for .. etc */ @@ -71,19 +74,21 @@ static const int max_test_dir_size = 20; /* size of above plus some for .. etc static void set_up_attribute_test(const char *testdirA) { int i; + BOOL ret; - ok(CreateDirectoryA(testdirA, NULL), - "couldn't create dir '%s', error %d\n", testdirA, GetLastError()); + ret = CreateDirectoryA(testdirA, NULL); + ok(ret, "couldn't create dir '%s', error %d\n", testdirA, GetLastError()); for (i=0; testfiles[i].name; i++) { char buf[MAX_PATH]; pRtlMultiByteToUnicodeN(testfiles[i].nameW, sizeof(testfiles[i].nameW), NULL, testfiles[i].name, strlen(testfiles[i].name)+1); + if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name, "..") == 0) + continue; sprintf(buf, "%s\\%s", testdirA, testfiles[i].name); - testfiles[i].nfound = 0; if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { - ok(CreateDirectoryA(buf, NULL), - "couldn't create dir '%s', error %d\n", buf, GetLastError()); + ret = CreateDirectoryA(buf, NULL); + ok(ret, "couldn't create dir '%s', error %d\n", buf, GetLastError()); } else { HANDLE h = CreateFileA(buf, GENERIC_READ|GENERIC_WRITE, @@ -95,6 +100,14 @@ static void set_up_attribute_test(const char *testdirA) } } +static void reset_found_files(void) +{ + int i; + + for (i = 0; testfiles[i].name; i++) + testfiles[i].nfound = 0; +} + /* Remove the given test directory and the attribute test files, if any */ static void tear_down_attribute_test(const char *testdirA) { @@ -103,6 +116,8 @@ static void tear_down_attribute_test(const char *testdirA) for (i=0; testfiles[i].name; i++) { int ret; char buf[MAX_PATH]; + if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name, "..") == 0) + continue; sprintf(buf, "%s\\%s", testdirA, testfiles[i].name); if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { ret = RemoveDirectory(buf); @@ -127,18 +142,18 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) WCHAR *nameW = dir_info->FileName; int namelen = dir_info->FileNameLength / sizeof(WCHAR); - if (nameW[0] == '.') - return; - for (i=0; testfiles[i].name; i++) { int len = strlen(testfiles[i].name); if (namelen != len || memcmp(nameW, testfiles[i].nameW, len*sizeof(WCHAR))) continue; - if (testfiles[i].todo) { - todo_wine - ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib); - } else { - ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib); + if (!testfiles[i].attr_done) { + if (testfiles[i].todo) { + todo_wine + ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib); + } else { + ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib); + } + testfiles[i].attr_done = TRUE; } testfiles[i].nfound++; break; @@ -146,12 +161,9 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) ok(testfiles[i].name != NULL, "unexpected file found\n"); } -static void test_NtQueryDirectoryFile(void) +static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char *testdirA, + BOOLEAN single_entry, BOOLEAN restart_flag) { - OBJECT_ATTRIBUTES attr; - UNICODE_STRING ntdirname; - char testdirA[MAX_PATH]; - WCHAR testdirW[MAX_PATH]; HANDLE dirh; IO_STATUS_BLOCK io; UINT data_pos; @@ -162,31 +174,19 @@ static void test_NtQueryDirectoryFile(void) int numfiles; int i; - /* Clean up from prior aborted run, if any, then set up test files */ - ok(GetTempPathA(MAX_PATH, testdirA), "couldn't get temp dir\n"); - strcat(testdirA, "NtQueryDirectoryFile.tmp"); - tear_down_attribute_test(testdirA); - set_up_attribute_test(testdirA); + reset_found_files(); /* Read the directory and note which files are found */ - pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA, strlen(testdirA)+1); - if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL)) - { - ok(0,"RtlDosPathNametoNtPathName_U failed\n"); - goto done; - } - InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); - status = pNtOpenFile( &dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, - FILE_OPEN, + status = pNtOpenFile( &dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, attr, &io, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_DIRECTORY_FILE); ok (status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%x, error %d\n", testdirA, status, GetLastError()); if (status != STATUS_SUCCESS) { skip("can't test if we can't open the directory\n"); - goto done; + return; } pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, sizeof(data), - FileBothDirectoryInformation, FALSE, NULL, TRUE ); + FileBothDirectoryInformation, single_entry, NULL, restart_flag ); ok (U(io).Status == STATUS_SUCCESS, "filed to query directory; status %x\n", U(io).Status); data_len = io.Information; ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n"); @@ -200,7 +200,7 @@ static void test_NtQueryDirectoryFile(void) if (dir_info->NextEntryOffset == 0) { pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, sizeof(data), - FileBothDirectoryInformation, FALSE, NULL, FALSE ); + FileBothDirectoryInformation, single_entry, NULL, FALSE ); if (U(io).Status == STATUS_NO_MORE_FILES) break; ok (U(io).Status == STATUS_SUCCESS, "filed to query directory; status %x\n", U(io).Status); @@ -216,10 +216,38 @@ static void test_NtQueryDirectoryFile(void) ok(numfiles < max_test_dir_size, "too many loops\n"); for (i=0; testfiles[i].name; i++) - ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found\n", - testfiles[i].nfound, testfiles[i].description); + ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found (ReturnSingleEntry=%d,RestartScan=%d)\n", + testfiles[i].nfound, testfiles[i].description, single_entry, restart_flag); pNtClose(dirh); +} + +static void test_NtQueryDirectoryFile(void) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING ntdirname; + char testdirA[MAX_PATH]; + WCHAR testdirW[MAX_PATH]; + + /* Clean up from prior aborted run, if any, then set up test files */ + ok(GetTempPathA(MAX_PATH, testdirA), "couldn't get temp dir\n"); + strcat(testdirA, "NtQueryDirectoryFile.tmp"); + tear_down_attribute_test(testdirA); + set_up_attribute_test(testdirA); + + pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA, strlen(testdirA)+1); + if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL)) + { + ok(0, "RtlDosPathNametoNtPathName_U failed\n"); + goto done; + } + InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); + + test_flags_NtQueryDirectoryFile(&attr, testdirA, FALSE, TRUE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, FALSE, FALSE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, TRUE, TRUE); + test_flags_NtQueryDirectoryFile(&attr, testdirA, TRUE, FALSE); + done: tear_down_attribute_test(testdirA); pRtlFreeUnicodeString(&ntdirname); diff --git a/rostests/winetests/ntdll/env.c b/rostests/winetests/ntdll/env.c index 82898412643..6bd15305e91 100755 --- a/rostests/winetests/ntdll/env.c +++ b/rostests/winetests/ntdll/env.c @@ -244,6 +244,7 @@ static void testExpand(void) us_dst.Buffer = NULL; nts = pRtlExpandEnvironmentStrings_U(small_env, &us_src, &us_dst, &ul); + ok(nts == STATUS_BUFFER_TOO_SMALL, "Call failed (%u)\n", nts); ok(ul == strlen(test->dst) * sizeof(WCHAR) + sizeof(WCHAR), "Wrong returned length for %s: %u\n", test->src, ul ); diff --git a/rostests/winetests/ntdll/error.c b/rostests/winetests/ntdll/error.c index 01c165dfa90..22194c6f40a 100755 --- a/rostests/winetests/ntdll/error.c +++ b/rostests/winetests/ntdll/error.c @@ -2,6 +2,7 @@ * Unit tests for RtlNtStatusToDosError function * * Copyright (c) 2002 Andriy Palamarchuk + * Copyright (c) 2010 André Hentschel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -156,6 +157,8 @@ static void run_error_tests(void) cmp(STATUS_CHILD_MUST_BE_VOLATILE, ERROR_CHILD_MUST_BE_VOLATILE); cmp(STATUS_REGISTRY_CORRUPT, ERROR_BADDB); cmp(STATUS_DLL_NOT_FOUND, ERROR_MOD_NOT_FOUND); + cmp2(STATUS_OPEN_FAILED, ERROR_NET_OPEN_FAILED); + cmp2(STATUS_IO_PRIVILEGE_FAILED, ERROR_IO_PRIVILEGE_FAILED); cmp(STATUS_DLL_INIT_FAILED, ERROR_DLL_INIT_FAILED); cmp2(STATUS_INVALID_IMPORT_OF_NON_DLL, ERROR_INVALID_IMPORT_OF_NON_DLL); cmp(STATUS_ORDINAL_NOT_FOUND, ERROR_INVALID_ORDINAL); @@ -221,7 +224,7 @@ static void run_error_tests(void) cmp(STATUS_WRONG_VOLUME, ERROR_WRONG_DISK); cmp(STATUS_NO_MEDIA, ERROR_NO_MEDIA_IN_DRIVE); cmp(STATUS_NO_MEDIA_IN_DEVICE, ERROR_NOT_READY); - cmp(STATUS_VOLUME_DISMOUNTED, ERROR_NOT_READY); + cmp2(STATUS_VOLUME_DISMOUNTED, ERROR_NOT_READY); cmp(STATUS_NONEXISTENT_SECTOR, ERROR_SECTOR_NOT_FOUND); cmp(STATUS_WORKING_SET_QUOTA, ERROR_WORKING_SET_QUOTA); cmp(STATUS_NO_MEMORY, ERROR_NOT_ENOUGH_MEMORY); @@ -329,6 +332,9 @@ static void run_error_tests(void) cmp(STATUS_INVALID_SID, ERROR_INVALID_SID); cmp(STATUS_INVALID_SECURITY_DESCR, ERROR_INVALID_SECURITY_DESCR); cmp(STATUS_PROCEDURE_NOT_FOUND, ERROR_PROC_NOT_FOUND); + cmp2(STATUS_INVALID_LDT_SIZE, ERROR_INVALID_LDT_SIZE); + cmp2(STATUS_INVALID_LDT_OFFSET, ERROR_INVALID_LDT_OFFSET); + cmp2(STATUS_INVALID_LDT_DESCRIPTOR, ERROR_INVALID_LDT_DESCRIPTOR); cmp(STATUS_BAD_INITIAL_PC, ERROR_BAD_EXE_FORMAT); cmp(STATUS_INVALID_FILE_FOR_SECTION, ERROR_BAD_EXE_FORMAT); cmp(STATUS_INVALID_IMAGE_FORMAT, ERROR_BAD_EXE_FORMAT); @@ -462,6 +468,23 @@ static void run_error_tests(void) cmp(STATUS_NO_QUOTAS_FOR_ACCOUNT, ERROR_NO_QUOTAS_FOR_ACCOUNT); cmp(STATUS_LOCAL_USER_SESSION_KEY, ERROR_LOCAL_USER_SESSION_KEY); cmp(STATUS_NULL_LM_PASSWORD, ERROR_NULL_LM_PASSWORD); + cmp2(STATUS_IMAGE_MACHINE_TYPE_MISMATCH, ERROR_IMAGE_MACHINE_TYPE_MISMATCH); + cmp2(STATUS_RECEIVE_PARTIAL, ERROR_RECEIVE_PARTIAL); + cmp2(STATUS_RECEIVE_EXPEDITED, ERROR_RECEIVE_EXPEDITED); + cmp2(STATUS_RECEIVE_PARTIAL_EXPEDITED, ERROR_RECEIVE_PARTIAL_EXPEDITED); + cmp2(STATUS_EVENT_DONE, ERROR_EVENT_DONE); + cmp2(STATUS_EVENT_PENDING, ERROR_EVENT_PENDING); + cmp2(STATUS_CHECKING_FILE_SYSTEM, ERROR_CHECKING_FILE_SYSTEM); + cmp2(STATUS_FATAL_APP_EXIT, ERROR_FATAL_APP_EXIT); + cmp2(STATUS_PREDEFINED_HANDLE, ERROR_PREDEFINED_HANDLE); + cmp2(STATUS_WAS_UNLOCKED, ERROR_WAS_UNLOCKED); + cmp2(STATUS_SERVICE_NOTIFICATION, ERROR_SERVICE_NOTIFICATION); + cmp2(STATUS_WAS_LOCKED, ERROR_WAS_LOCKED); + cmp2(STATUS_LOG_HARD_ERROR, ERROR_LOG_HARD_ERROR); + cmp2(STATUS_ALREADY_WIN32, ERROR_ALREADY_WIN32); + cmp2(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE); + cmp2(STATUS_NO_YIELD_PERFORMED, ERROR_NO_YIELD_PERFORMED); + cmp2(STATUS_TIMER_RESUME_IGNORED, ERROR_TIMER_RESUME_IGNORED); cmp(STATUS_BAD_INHERITANCE_ACL, ERROR_BAD_INHERITANCE_ACL); cmp(STATUS_INVALID_GROUP_ATTRIBUTES, ERROR_INVALID_GROUP_ATTRIBUTES); cmp(STATUS_BAD_IMPERSONATION_LEVEL, ERROR_BAD_IMPERSONATION_LEVEL); @@ -511,6 +534,7 @@ static void run_error_tests(void) cmp(STATUS_TOO_MANY_SIDS, ERROR_TOO_MANY_SIDS); cmp(STATUS_LM_CROSS_ENCRYPTION_REQUIRED, ERROR_LM_CROSS_ENCRYPTION_REQUIRED); cmp(STATUS_MESSAGE_NOT_FOUND, ERROR_MR_MID_NOT_FOUND); + cmp2(STATUS_CONTROL_C_EXIT, ERROR_CONTROL_C_EXIT); cmp(STATUS_LOCAL_DISCONNECT, ERROR_NETNAME_DELETED); cmp(STATUS_REMOTE_DISCONNECT, ERROR_NETNAME_DELETED); cmp(STATUS_REMOTE_RESOURCES, ERROR_REM_NOT_LIST); @@ -518,6 +542,14 @@ static void run_error_tests(void) cmp(STATUS_LINK_TIMEOUT, ERROR_UNEXP_NET_ERR); cmp(STATUS_INVALID_CONNECTION, ERROR_UNEXP_NET_ERR); cmp(STATUS_INVALID_ADDRESS, ERROR_UNEXP_NET_ERR); + cmp2(STATUS_MISSING_SYSTEMFILE, ERROR_MISSING_SYSTEMFILE); + cmp2(STATUS_PAGEFILE_CREATE_FAILED, ERROR_PAGEFILE_CREATE_FAILED); + cmp2(STATUS_UNHANDLED_EXCEPTION, ERROR_UNHANDLED_EXCEPTION); + cmp2(STATUS_APP_INIT_FAILURE, ERROR_APP_INIT_FAILURE); + cmp2(STATUS_NO_PAGEFILE, ERROR_NO_PAGEFILE); + cmp2(STATUS_ILLEGAL_FLOAT_CONTEXT, ERROR_ILLEGAL_FLOAT_CONTEXT); + cmp2(STATUS_NO_EVENT_PAIR, ERROR_NO_EVENT_PAIR); + cmp2(STATUS_DOMAIN_CTRLR_CONFIG_ERROR, ERROR_DOMAIN_CTRLR_CONFIG_ERROR); cmp(STATUS_IO_DEVICE_ERROR, ERROR_IO_DEVICE); cmp(STATUS_DEVICE_PROTOCOL_ERROR, ERROR_IO_DEVICE); cmp(STATUS_DRIVER_INTERNAL_ERROR, ERROR_IO_DEVICE); @@ -904,9 +936,36 @@ static void run_error_tests(void) cmp2(STATUS_SXS_MANIFEST_PARSE_ERROR, ERROR_SXS_MANIFEST_PARSE_ERROR); cmp2(STATUS_SXS_ACTIVATION_CONTEXT_DISABLED, ERROR_SXS_ACTIVATION_CONTEXT_DISABLED); cmp2(STATUS_SXS_KEY_NOT_FOUND, ERROR_SXS_KEY_NOT_FOUND); + cmp2(STATUS_SXS_VERSION_CONFLICT, ERROR_SXS_VERSION_CONFLICT); cmp2(STATUS_SXS_WRONG_SECTION_TYPE, ERROR_SXS_WRONG_SECTION_TYPE); cmp2(STATUS_SXS_THREAD_QUERIES_DISABLED, ERROR_SXS_THREAD_QUERIES_DISABLED); + cmp2(STATUS_SXS_ASSEMBLY_MISSING, ERROR_SXS_ASSEMBLY_MISSING); cmp2(STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET, ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET); + cmp2(STATUS_SXS_EARLY_DEACTIVATION, ERROR_SXS_EARLY_DEACTIVATION); + cmp2(STATUS_SXS_INVALID_DEACTIVATION, ERROR_SXS_INVALID_DEACTIVATION); + cmp2(STATUS_SXS_MULTIPLE_DEACTIVATION, ERROR_SXS_MULTIPLE_DEACTIVATION); + cmp2(STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY); + cmp2(STATUS_SXS_PROCESS_TERMINATION_REQUESTED, ERROR_SXS_PROCESS_TERMINATION_REQUESTED); + cmp2(STATUS_SXS_CORRUPT_ACTIVATION_STACK, ERROR_SXS_CORRUPT_ACTIVATION_STACK); + cmp2(STATUS_SXS_CORRUPTION, ERROR_SXS_CORRUPTION); + cmp2(STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE); + cmp2(STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME); + cmp2(STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE); + cmp2(STATUS_SXS_IDENTITY_PARSE_ERROR, ERROR_SXS_IDENTITY_PARSE_ERROR); + cmp2(STATUS_SXS_COMPONENT_STORE_CORRUPT, ERROR_SXS_COMPONENT_STORE_CORRUPT); + cmp2(STATUS_SXS_FILE_HASH_MISMATCH, ERROR_SXS_FILE_HASH_MISMATCH); + cmp2(STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT); + cmp2(STATUS_SXS_IDENTITIES_DIFFERENT, ERROR_SXS_IDENTITIES_DIFFERENT); + cmp2(STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT); + cmp2(STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY, ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY); + cmp2(STATUS_ADVANCED_INSTALLER_FAILED, ERROR_ADVANCED_INSTALLER_FAILED); + cmp2(STATUS_XML_ENCODING_MISMATCH, ERROR_XML_ENCODING_MISMATCH); + cmp2(STATUS_SXS_MANIFEST_TOO_BIG, ERROR_SXS_MANIFEST_TOO_BIG); + cmp2(STATUS_SXS_SETTING_NOT_REGISTERED, ERROR_SXS_SETTING_NOT_REGISTERED); + cmp2(STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE, ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE); + cmp2(STATUS_SXS_PRIMITIVE_INSTALLER_FAILED, ERROR_SMI_PRIMITIVE_INSTALLER_FAILED); + cmp2(STATUS_GENERIC_COMMAND_FAILED, ERROR_GENERIC_COMMAND_FAILED); + cmp2(STATUS_SXS_FILE_HASH_MISSING, ERROR_SXS_FILE_HASH_MISSING); cmp2(STATUS_REDIRECTOR_STARTED, ERROR_SERVICE_ALREADY_RUNNING); cmp2(STATUS_AUDITING_DISABLED, ERROR_AUDITING_DISABLED); cmp2(STATUS_CLUSTER_NODE_ALREADY_UP, ERROR_CLUSTER_NODE_ALREADY_UP); diff --git a/rostests/winetests/ntdll/exception.c b/rostests/winetests/ntdll/exception.c index 20369f90f73..ac138055347 100644 --- a/rostests/winetests/ntdll/exception.c +++ b/rostests/winetests/ntdll/exception.c @@ -72,13 +72,16 @@ static BOOL is_wow64; static const struct exception { - BYTE code[18]; /* asm code */ - BYTE offset; /* offset of faulting instruction */ - BYTE length; /* length of faulting instruction */ - BOOL wow64_broken; /* broken on Wow64, should be skipped */ - NTSTATUS status; /* expected status code */ - DWORD nb_params; /* expected number of parameters */ - DWORD params[4]; /* expected parameters */ + BYTE code[18]; /* asm code */ + BYTE offset; /* offset of faulting instruction */ + BYTE length; /* length of faulting instruction */ + BOOL wow64_broken; /* broken on Wow64, should be skipped */ + NTSTATUS status; /* expected status code */ + DWORD nb_params; /* expected number of parameters */ + DWORD params[4]; /* expected parameters */ + NTSTATUS alt_status; /* alternative status code */ + DWORD alt_nb_params; /* alternative number of parameters */ + DWORD alt_params[4]; /* alternative parameters */ } exceptions[] = { /* 0 */ @@ -137,66 +140,67 @@ static const struct exception 6, 6, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test moving %cs -> %ss */ - { { 0x0e, 0x17, 0x58, 0xc3 }, /* 18: pushl %cs; popl %ss; popl %eax; ret */ + { { 0x0e, 0x17, 0x58, 0xc3 }, /* pushl %cs; popl %ss; popl %eax; ret */ 1, 1, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* 20 */ /* test overlong instruction (limit is 15 bytes, 5 on Win7) */ { { 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0xfa,0xc3 }, - 0, 16, TRUE, STATUS_ILLEGAL_INSTRUCTION, 0 }, + 0, 16, TRUE, STATUS_ILLEGAL_INSTRUCTION, 0, { 0 }, + STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, { { 0x64,0x64,0x64,0x64,0xfa,0xc3 }, 0, 5, TRUE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test invalid interrupt */ - { { 0xcd, 0xff, 0xc3 }, /* 21: int $0xff; ret */ + { { 0xcd, 0xff, 0xc3 }, /* int $0xff; ret */ 0, 2, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test moves to/from Crx */ - { { 0x0f, 0x20, 0xc0, 0xc3 }, /* 22: movl %cr0,%eax; ret */ + { { 0x0f, 0x20, 0xc0, 0xc3 }, /* movl %cr0,%eax; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x20, 0xe0, 0xc3 }, /* 23: movl %cr4,%eax; ret */ + { { 0x0f, 0x20, 0xe0, 0xc3 }, /* movl %cr4,%eax; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* 25 */ - { { 0x0f, 0x22, 0xc0, 0xc3 }, /* 24: movl %eax,%cr0; ret */ + { { 0x0f, 0x22, 0xc0, 0xc3 }, /* movl %eax,%cr0; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x22, 0xe0, 0xc3 }, /* 25: movl %eax,%cr4; ret */ + { { 0x0f, 0x22, 0xe0, 0xc3 }, /* movl %eax,%cr4; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test moves to/from Drx */ - { { 0x0f, 0x21, 0xc0, 0xc3 }, /* 26: movl %dr0,%eax; ret */ + { { 0x0f, 0x21, 0xc0, 0xc3 }, /* movl %dr0,%eax; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x21, 0xc8, 0xc3 }, /* 27: movl %dr1,%eax; ret */ + { { 0x0f, 0x21, 0xc8, 0xc3 }, /* movl %dr1,%eax; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x21, 0xf8, 0xc3 }, /* 28: movl %dr7,%eax; ret */ + { { 0x0f, 0x21, 0xf8, 0xc3 }, /* movl %dr7,%eax; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* 30 */ - { { 0x0f, 0x23, 0xc0, 0xc3 }, /* 29: movl %eax,%dr0; ret */ + { { 0x0f, 0x23, 0xc0, 0xc3 }, /* movl %eax,%dr0; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x23, 0xc8, 0xc3 }, /* 30: movl %eax,%dr1; ret */ + { { 0x0f, 0x23, 0xc8, 0xc3 }, /* movl %eax,%dr1; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, - { { 0x0f, 0x23, 0xf8, 0xc3 }, /* 31: movl %eax,%dr7; ret */ + { { 0x0f, 0x23, 0xf8, 0xc3 }, /* movl %eax,%dr7; ret */ 0, 3, FALSE, STATUS_PRIVILEGED_INSTRUCTION, 0 }, /* test memory reads */ - { { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* 32: movl 0xfffffffc,%eax; ret */ + { { 0xa1, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffc,%eax; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffc } }, - { { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* 33: movl 0xfffffffd,%eax; ret */ + { { 0xa1, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffd,%eax; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffd } }, /* 35 */ - { { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* 34: movl 0xfffffffe,%eax; ret */ + { { 0xa1, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xfffffffe,%eax; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xfffffffe } }, - { { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* 35: movl 0xffffffff,%eax; ret */ + { { 0xa1, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl 0xffffffff,%eax; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } }, /* test memory writes */ - { { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* 36: movl %eax,0xfffffffc; ret */ + { { 0xa3, 0xfc, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffc; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffc } }, - { { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* 37: movl %eax,0xfffffffd; ret */ + { { 0xa3, 0xfd, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffd; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffd } }, - { { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* 38: movl %eax,0xfffffffe; ret */ + { { 0xa3, 0xfe, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xfffffffe; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xfffffffe } }, /* 40 */ - { { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* 39: movl %eax,0xffffffff; ret */ + { { 0xa3, 0xff, 0xff, 0xff, 0xff, 0xc3 }, /* movl %eax,0xffffffff; ret */ 0, 5, FALSE, STATUS_ACCESS_VIOLATION, 2, { 1, 0xffffffff } }, /* test exception with cleared %ds and %es (broken on Wow64) */ @@ -389,14 +393,23 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram trace( "exception %u: %x flags:%x addr:%p\n", entry, rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); - ok( rec->ExceptionCode == except->status, + ok( rec->ExceptionCode == except->status || + (except->alt_status != 0 && rec->ExceptionCode == except->alt_status), "%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode, except->status ); ok( rec->ExceptionAddress == (char*)code_mem + except->offset, "%u: Wrong exception address %p/%p\n", entry, rec->ExceptionAddress, (char*)code_mem + except->offset ); - ok( rec->NumberParameters == except->nb_params, - "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); + if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status) + { + ok( rec->NumberParameters == except->nb_params, + "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); + } + else + { + ok( rec->NumberParameters == except->alt_nb_params, + "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); + } /* Most CPUs (except Intel Core apparently) report a segment limit violation */ /* instead of page faults for accesses beyond 0xffffffff */ @@ -414,10 +427,20 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram goto skip_params; } - for (i = 0; i < rec->NumberParameters; i++) - ok( rec->ExceptionInformation[i] == except->params[i], - "%u: Wrong parameter %d: %lx/%x\n", - entry, i, rec->ExceptionInformation[i], except->params[i] ); + if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status) + { + for (i = 0; i < rec->NumberParameters; i++) + ok( rec->ExceptionInformation[i] == except->params[i], + "%u: Wrong parameter %d: %lx/%x\n", + entry, i, rec->ExceptionInformation[i], except->params[i] ); + } + else + { + for (i = 0; i < rec->NumberParameters; i++) + ok( rec->ExceptionInformation[i] == except->alt_params[i], + "%u: Wrong parameter %d: %lx/%x\n", + entry, i, rec->ExceptionInformation[i], except->alt_params[i] ); + } skip_params: /* don't handle exception if it's not the address we expected */ @@ -451,20 +474,47 @@ static void test_prot_fault(void) } } +struct dbgreg_test { + DWORD dr0, dr1, dr2, dr3, dr6, dr7; +}; + /* test handling of debug registers */ static DWORD dreg_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { + const struct dbgreg_test *test = *(const struct dbgreg_test **)(frame + 1); + context->Eip += 2; /* Skips the popl (%eax) */ - context->Dr0 = 0x42424242; - context->Dr1 = 0; - context->Dr2 = 0; - context->Dr3 = 0; - context->Dr6 = 0; - context->Dr7 = 0x155; + context->Dr0 = test->dr0; + context->Dr1 = test->dr1; + context->Dr2 = test->dr2; + context->Dr3 = test->dr3; + context->Dr6 = test->dr6; + context->Dr7 = test->dr7; return ExceptionContinueExecution; } +#define CHECK_DEBUG_REG(n, m) \ + ok((ctx.Dr##n & m) == test->dr##n, "(%d) failed to set debug register " #n " to %x, got %x\n", \ + test_num, test->dr##n, ctx.Dr##n) + +static void check_debug_registers(int test_num, const struct dbgreg_test *test) +{ + CONTEXT ctx; + NTSTATUS status; + + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + status = pNtGetContextThread(GetCurrentThread(), &ctx); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status); + + CHECK_DEBUG_REG(0, ~0); + CHECK_DEBUG_REG(1, ~0); + CHECK_DEBUG_REG(2, ~0); + CHECK_DEBUG_REG(3, ~0); + CHECK_DEBUG_REG(6, 0x0f); + CHECK_DEBUG_REG(7, ~0xdc00); +} + static const BYTE segfault_code[5] = { 0x31, 0xc0, /* xor %eax,%eax */ 0x8f, 0x00, /* popl (%eax) - cause exception */ @@ -621,6 +671,7 @@ static void test_exceptions(void) { CONTEXT ctx; NTSTATUS res; + struct dbgreg_test dreg_test; if (!pNtGetContextThread || !pNtSetContextThread) { @@ -629,13 +680,21 @@ static void test_exceptions(void) } /* test handling of debug registers */ - run_exception_test(dreg_handler, NULL, &segfault_code, sizeof(segfault_code), 0); + memset(&dreg_test, 0, sizeof(dreg_test)); - ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; - res = pNtGetContextThread(GetCurrentThread(), &ctx); - ok (res == STATUS_SUCCESS,"NtGetContextThread failed with %x\n", res); - ok(ctx.Dr0 == 0x42424242,"failed to set debugregister 0 to 0x42424242, got %x\n", ctx.Dr0); - ok((ctx.Dr7 & ~0xdc00) == 0x155,"failed to set debugregister 7 to 0x155, got %x\n", ctx.Dr7); + dreg_test.dr0 = 0x42424240; + dreg_test.dr2 = 0x126bb070; + dreg_test.dr3 = 0x0badbad0; + dreg_test.dr7 = 0xffff0115; + run_exception_test(dreg_handler, &dreg_test, &segfault_code, sizeof(segfault_code), 0); + check_debug_registers(1, &dreg_test); + + dreg_test.dr0 = 0x42424242; + dreg_test.dr2 = 0x100f0fe7; + dreg_test.dr3 = 0x0abebabe; + dreg_test.dr7 = 0x115; + run_exception_test(dreg_handler, &dreg_test, &segfault_code, sizeof(segfault_code), 0); + check_debug_registers(2, &dreg_test); /* test single stepping behavior */ got_exception = 0; @@ -658,7 +717,7 @@ static void test_exceptions(void) ctx.Dr7 = 3; ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; res = pNtSetContextThread( GetCurrentThread(), &ctx); - ok( res == STATUS_SUCCESS, "NtSetContextThread faild with %x\n", res); + ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res); got_exception = 0; run_exception_test(bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0); @@ -737,7 +796,7 @@ static void test_debugger(void) if (counter > 100) { - ok(FALSE, "got way too many exceptions, probaby caught in a infinite loop, terminating child\n"); + ok(FALSE, "got way too many exceptions, probably caught in a infinite loop, terminating child\n"); pNtTerminateProcess(pi.hProcess, 1); } else if (counter >= 2) /* skip startup breakpoint */ @@ -805,8 +864,10 @@ static void test_debugger(void) } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT); winetest_wait_child_process( pi.hProcess ); - ok(CloseHandle(pi.hThread) != 0, "error %u\n", GetLastError()); - ok(CloseHandle(pi.hProcess) != 0, "error %u\n", GetLastError()); + ret = CloseHandle(pi.hThread); + ok(ret, "error %u\n", GetLastError()); + ret = CloseHandle(pi.hProcess); + ok(ret, "error %u\n", GetLastError()); return; } diff --git a/rostests/winetests/ntdll/file.c b/rostests/winetests/ntdll/file.c index 28287945f60..e299560eb30 100644 --- a/rostests/winetests/ntdll/file.c +++ b/rostests/winetests/ntdll/file.c @@ -3,6 +3,7 @@ * Copyright 2007 Jeff Latimer * Copyright 2007 Andrey Turkin * Copyright 2008 Jeff Zaroyko + * Copyright 2011 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,6 +36,7 @@ #include "wine/test.h" #include "winternl.h" #include "winuser.h" +#include "winioctl.h" #ifndef IO_COMPLETION_ALL_ACCESS #define IO_COMPLETION_ALL_ACCESS 0x001F0003 @@ -75,6 +77,7 @@ static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS); static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK, PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN); +static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS); static inline BOOL is_signaled( HANDLE obj ) { @@ -112,9 +115,9 @@ static HANDLE create_temp_file( ULONG flags ) #define CKEY_FIRST 0x1030341 #define CKEY_SECOND 0x132E46 -ULONG_PTR completionKey; -IO_STATUS_BLOCK ioSb; -ULONG_PTR completionValue; +static ULONG_PTR completionKey; +static IO_STATUS_BLOCK ioSb; +static ULONG_PTR completionValue; static ULONG get_pending_msgs(HANDLE h) { @@ -157,8 +160,10 @@ static void create_file_test(void) { static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t', '\\','f','a','i','l','i','n','g',0}; + static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0}; + static const WCHAR pipeInvalidNameW[] = {'a','|','b',0}; NTSTATUS status; - HANDLE dir; + HANDLE dir, file; WCHAR path[MAX_PATH]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; @@ -246,6 +251,35 @@ static void create_file_test(void) todo_wine ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + /* Invalid chars in file/dirnames */ + pRtlDosPathNameToNtPathName_U(questionmarkInvalidNameW, &nameW, NULL, NULL); + attr.ObjectName = &nameW; + status = pNtCreateFile(&dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0, + FILE_SHARE_READ, FILE_CREATE, + FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + ok(status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status); + + status = pNtCreateFile(&file, GENERIC_WRITE|SYNCHRONIZE, &attr, &io, NULL, 0, + 0, FILE_CREATE, + FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + ok(status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status); + + pRtlDosPathNameToNtPathName_U(pipeInvalidNameW, &nameW, NULL, NULL); + attr.ObjectName = &nameW; + status = pNtCreateFile(&dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0, + FILE_SHARE_READ, FILE_CREATE, + FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + ok(status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status); + + status = pNtCreateFile(&file, GENERIC_WRITE|SYNCHRONIZE, &attr, &io, NULL, 0, + 0, FILE_CREATE, + FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + ok(status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status); } static void open_file_test(void) @@ -454,6 +488,7 @@ static void read_file_test(void) char buffer[128]; LARGE_INTEGER offset; HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL ); + BOOL ret; buffer[0] = 1; @@ -597,8 +632,8 @@ static void read_file_test(void) CloseHandle( read ); if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - ok(DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS), - "Failed to duplicate handle: %d\n", GetLastError()); + ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS); + ok(ret, "Failed to duplicate handle: %d\n", GetLastError()); apc_count = 0; U(iosb).Status = 0xdeadbabe; @@ -711,6 +746,7 @@ static void read_file_test(void) ResetEvent( event ); status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL ); ok( status == STATUS_SUCCESS || status == STATUS_PENDING, "wrong status %x\n", status ); + if (status == STATUS_PENDING) WaitForSingleObject( event, 1000 ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); ok( is_signaled( event ), "event is signaled\n" ); @@ -727,6 +763,7 @@ static void read_file_test(void) ok( status == STATUS_SUCCESS || status == STATUS_PENDING, /* vista */ "wrong status %x\n", status ); + if (status == STATUS_PENDING) WaitForSingleObject( event, 1000 ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); ok( is_signaled( event ), "event is signaled\n" ); @@ -742,6 +779,7 @@ static void read_file_test(void) status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL ); if (status == STATUS_PENDING) /* vista */ { + WaitForSingleObject( event, 1000 ); 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 signaled\n" ); @@ -772,6 +810,7 @@ static void read_file_test(void) status == STATUS_SUCCESS || status == STATUS_PENDING, /* vista */ "wrong status %x\n", status ); + if (status == STATUS_PENDING) WaitForSingleObject( event, 1000 ); ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status ); ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information ); ok( is_signaled( event ), "event is signaled\n" ); @@ -813,6 +852,46 @@ static void read_file_test(void) CloseHandle( event ); } +static void append_file_test(void) +{ + const char text[] = "foobar"; + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK iosb; + DWORD written; + char buffer[128]; + + GetTempFileNameA( ".", "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; + + 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"); + + CloseHandle(handle); +} + static void nt_mailslot_test(void) { HANDLE hslot; @@ -858,7 +937,7 @@ static void nt_mailslot_test(void) "rc = %x not STATUS_SUCCESS or STATUS_INVALID_PARAMETER\n", rc); ok( hslot != 0, "Handle is invalid\n"); - if ( rc == STATUS_SUCCESS ) rc = pNtClose(hslot); + if ( rc == STATUS_SUCCESS ) pNtClose(hslot); /* * Test that the length field is checked properly @@ -947,8 +1026,11 @@ static void test_iocp_fileio(HANDLE h) ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" ); if (hPipeClt != INVALID_HANDLE_VALUE) { + U(iosb).Status = 0xdeadbeef; res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation ); ok( res == STATUS_INVALID_PARAMETER, "Unexpected NtSetInformationFile on non-overlapped handle: %x\n", res ); + ok( U(iosb).Status == STATUS_INVALID_PARAMETER /* 98 */ || U(iosb).Status == 0xdeadbeef /* NT4+ */, + "Unexpected iosb.Status on non-overlapped handle: %x\n", U(iosb).Status ); CloseHandle(hPipeClt); } CloseHandle( hPipeSrv ); @@ -968,7 +1050,8 @@ static void test_iocp_fileio(HANDLE h) DWORD read; long count; - NTSTATUS res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation ); + U(iosb).Status = 0xdeadbeef; + res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation ); ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res ); ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n", U(iosb).Status ); @@ -1047,8 +1130,10 @@ static void test_file_basic_information(void) /* Clear fbi to avoid setting times */ memset(&fbi, 0, sizeof(fbi)); fbi.FileAttributes = FILE_ATTRIBUTE_SYSTEM; + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + ok ( res == STATUS_SUCCESS, "can't set system attribute, NtSetInformationFile returned %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status is %x\n", U(io).Status ); memset(&fbi, 0, sizeof(fbi)); res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); @@ -1058,8 +1143,10 @@ static void test_file_basic_information(void) /* Then HIDDEN */ memset(&fbi, 0, sizeof(fbi)); fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN; + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + ok ( res == STATUS_SUCCESS, "can't set system attribute, NtSetInformationFile returned %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status is %x\n", U(io).Status ); memset(&fbi, 0, sizeof(fbi)); res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); @@ -1069,8 +1156,10 @@ static void test_file_basic_information(void) /* Check NORMAL last of all (to make sure we can clear attributes) */ memset(&fbi, 0, sizeof(fbi)); fbi.FileAttributes = FILE_ATTRIBUTE_NORMAL; + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't set normal attribute\n"); + ok ( res == STATUS_SUCCESS, "can't set normal attribute, NtSetInformationFile returned %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set normal attribute, io.Status is %x\n", U(io).Status ); memset(&fbi, 0, sizeof(fbi)); res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); @@ -1107,10 +1196,14 @@ static void test_file_all_information(void) /* Clear fbi to avoid setting times */ memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_SYSTEM; + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); - ok ( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "shouldn't be able to set FileAllInformation, res %x\n", res); + ok ( res == STATUS_INVALID_INFO_CLASS || broken(res == STATUS_NOT_IMPLEMENTED), "shouldn't be able to set FileAllInformation, res %x\n", res); + todo_wine ok ( U(io).Status == 0xdeadbeef, "shouldn't be able to set FileAllInformation, io.Status is %x\n", U(io).Status); + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + ok ( res == STATUS_SUCCESS, "can't set system attribute, res: %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status: %x\n", U(io).Status ); memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); @@ -1120,8 +1213,10 @@ static void test_file_all_information(void) /* Then HIDDEN */ memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_HIDDEN; + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't set system attribute\n"); + ok ( res == STATUS_SUCCESS, "can't set system attribute, res: %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status: %x\n", U(io).Status ); memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); @@ -1131,8 +1226,10 @@ static void test_file_all_information(void) /* Check NORMAL last of all (to make sure we can clear attributes) */ memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL; + U(io).Status = 0xdeadbeef; res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't set normal attribute\n"); + ok ( res == STATUS_SUCCESS, "can't set system attribute, res: %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status: %x\n", U(io).Status ); memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); @@ -1440,6 +1537,145 @@ static void test_file_all_name_information(void) HeapFree( GetProcessHeap(), 0, file_name ); } +static void test_query_volume_information_file(void) +{ + NTSTATUS status; + HANDLE dir; + WCHAR path[MAX_PATH]; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + UNICODE_STRING nameW; + FILE_FS_VOLUME_INFORMATION *ffvi; + BYTE buf[sizeof(FILE_FS_VOLUME_INFORMATION) + MAX_PATH * sizeof(WCHAR)]; + + GetWindowsDirectoryW( path, MAX_PATH ); + pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = pNtOpenFile( &dir, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + pRtlFreeUnicodeString( &nameW ); + + ZeroMemory( buf, sizeof(buf) ); + U(io).Status = 0xdadadada; + io.Information = 0xcacacaca; + + status = pNtQueryVolumeInformationFile( dir, &io, buf, sizeof(buf), FileFsVolumeInformation ); + + ffvi = (FILE_FS_VOLUME_INFORMATION *)buf; + +todo_wine +{ + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", status); + ok(U(io).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", U(io).Status); + + ok(io.Information == (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength), + "expected %d, got %lu\n", (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength), + io.Information); + + ok(ffvi->VolumeCreationTime.QuadPart != 0, "Missing VolumeCreationTime\n"); + ok(ffvi->VolumeSerialNumber != 0, "Missing VolumeSerialNumber\n"); + ok(ffvi->SupportsObjects == 1,"expected 1, got %d\n", ffvi->SupportsObjects); +} + ok(ffvi->VolumeLabelLength == lstrlenW(ffvi->VolumeLabel) * sizeof(WCHAR), "got %d\n", ffvi->VolumeLabelLength); + + trace("VolumeSerialNumber: %x VolumeLabelName: %s\n", ffvi->VolumeSerialNumber, wine_dbgstr_w(ffvi->VolumeLabel)); + + CloseHandle( dir ); +} + +static void test_NtCreateFile(void) +{ + static const struct test_data + { + DWORD disposition, attrib_in, status, result, attrib_out, needs_cleanup; + } td[] = + { + /* 0*/{ FILE_CREATE, FILE_ATTRIBUTE_READONLY, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE }, + /* 1*/{ FILE_CREATE, 0, STATUS_OBJECT_NAME_COLLISION, 0, 0, TRUE }, + /* 2*/{ FILE_CREATE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE }, + /* 3*/{ FILE_OPEN, FILE_ATTRIBUTE_READONLY, 0, FILE_OPENED, FILE_ATTRIBUTE_ARCHIVE, TRUE }, + /* 4*/{ FILE_OPEN, FILE_ATTRIBUTE_READONLY, STATUS_OBJECT_NAME_NOT_FOUND, 0, 0, FALSE }, + /* 5*/{ FILE_OPEN_IF, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE }, + /* 6*/{ FILE_OPEN_IF, FILE_ATTRIBUTE_READONLY, 0, FILE_OPENED, FILE_ATTRIBUTE_ARCHIVE, TRUE }, + /* 7*/{ FILE_OPEN_IF, FILE_ATTRIBUTE_READONLY, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE }, + /* 8*/{ FILE_OPEN_IF, 0, 0, FILE_OPENED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE }, + /* 9*/{ FILE_OVERWRITE, 0, STATUS_ACCESS_DENIED, 0, 0, TRUE }, + /*10*/{ FILE_OVERWRITE, 0, STATUS_OBJECT_NAME_NOT_FOUND, 0, 0, FALSE }, + /*11*/{ FILE_CREATE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE }, + /*12*/{ FILE_OVERWRITE, FILE_ATTRIBUTE_READONLY, 0, FILE_OVERWRITTEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE }, + /*13*/{ FILE_OVERWRITE_IF, 0, STATUS_ACCESS_DENIED, 0, 0, TRUE }, + /*14*/{ FILE_OVERWRITE_IF, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE }, + /*15*/{ FILE_OVERWRITE_IF, FILE_ATTRIBUTE_READONLY, 0, FILE_OVERWRITTEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE }, + /*16*/{ FILE_SUPERSEDE, 0, 0, FILE_SUPERSEDED, FILE_ATTRIBUTE_ARCHIVE, FALSE }, + /*17*/{ FILE_SUPERSEDE, FILE_ATTRIBUTE_READONLY, 0, FILE_SUPERSEDED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, TRUE }, + /*18*/{ FILE_SUPERSEDE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, TRUE } + }; + static const WCHAR fooW[] = {'f','o','o',0}; + static const WCHAR dotW[] = {'.',0}; + NTSTATUS status; + HANDLE handle; + WCHAR path[MAX_PATH]; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + UNICODE_STRING nameW; + DWORD ret, i; + + GetTempFileNameW(dotW, fooW, 0, path); + DeleteFileW(path); + pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL); + + attr.Length = sizeof(attr); + attr.RootDirectory = NULL; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) + { + status = pNtCreateFile(&handle, GENERIC_READ, &attr, &io, NULL, + td[i].attrib_in, FILE_SHARE_READ|FILE_SHARE_WRITE, + td[i].disposition, 0, NULL, 0); + + ok(status == td[i].status, "%d: expected %#x got %#x\n", i, td[i].status, status); + + if (!status) + { + ok(io.Information == td[i].result,"%d: expected %#x got %#lx\n", i, td[i].result, io.Information); + + ret = GetFileAttributesW(path); + ret &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; + /* FIXME: leave only 'else' case below once Wine is fixed */ + if (ret != td[i].attrib_out) + { + todo_wine + ok(ret == td[i].attrib_out, "%d: expected %#x got %#x\n", i, td[i].attrib_out, ret); + SetFileAttributesW(path, td[i].attrib_out); + } + else + ok(ret == td[i].attrib_out, "%d: expected %#x got %#x\n", i, td[i].attrib_out, ret); + + CloseHandle(handle); + } + + if (td[i].needs_cleanup) + { + SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE); + DeleteFileW(path); + } + } + + SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE); + DeleteFileW( path ); +} + START_TEST(file) { HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); @@ -1474,11 +1710,14 @@ START_TEST(file) pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile"); pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); + pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll, "NtQueryVolumeInformationFile"); + test_NtCreateFile(); create_file_test(); open_file_test(); delete_file_test(); read_file_test(); + append_file_test(); nt_mailslot_test(); test_iocompletion(); test_file_basic_information(); @@ -1486,4 +1725,5 @@ START_TEST(file) test_file_both_information(); test_file_name_information(); test_file_all_name_information(); + test_query_volume_information_file(); } diff --git a/rostests/winetests/ntdll/info.c b/rostests/winetests/ntdll/info.c index 74ce71084b0..ec1ce3d2312 100755 --- a/rostests/winetests/ntdll/info.c +++ b/rostests/winetests/ntdll/info.c @@ -28,6 +28,11 @@ static NTSTATUS (WINAPI * pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PV static NTSTATUS (WINAPI * pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG); static NTSTATUS (WINAPI * pNtSetInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG); static NTSTATUS (WINAPI * pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); +static NTSTATUS (WINAPI * pNtQueryVirtualMemory)(HANDLE, LPCVOID, MEMORY_INFORMATION_CLASS , PVOID , SIZE_T , SIZE_T *); +static NTSTATUS (WINAPI * pNtCreateSection)(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,const LARGE_INTEGER*,ULONG,ULONG,HANDLE); +static NTSTATUS (WINAPI * pNtMapViewOfSection)(HANDLE,HANDLE,PVOID*,ULONG,SIZE_T,const LARGE_INTEGER*,SIZE_T*,SECTION_INHERIT,ULONG,ULONG); +static NTSTATUS (WINAPI * pNtUnmapViewOfSection)(HANDLE,PVOID); +static NTSTATUS (WINAPI * pNtClose)(HANDLE); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static BOOL is_wow64; @@ -61,6 +66,11 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtSetInformationProcess); NTDLL_GET_PROC(NtSetInformationThread); NTDLL_GET_PROC(NtReadVirtualMemory); + NTDLL_GET_PROC(NtQueryVirtualMemory); + NTDLL_GET_PROC(NtClose); + NTDLL_GET_PROC(NtCreateSection); + NTDLL_GET_PROC(NtMapViewOfSection); + NTDLL_GET_PROC(NtUnmapViewOfSection); pIsWow64Process = (void *)GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process"); if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; @@ -198,6 +208,7 @@ static void test_query_timeofday(void) sti.uCurrentTimeZoneId = 0xdeadbeef; status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 28, &ReturnLength); + ok(status == STATUS_SUCCESS || broken(status == STATUS_INFO_LENGTH_MISMATCH /* NT4 */), "Expected STATUS_SUCCESS, got %08x\n", status); ok( 0xdeadbeef == sti.uCurrentTimeZoneId, "This part of the buffer should not have been filled\n"); status = pNtQuerySystemInformation(SystemTimeOfDayInformation, &sti, 32, &ReturnLength); @@ -356,6 +367,7 @@ static void test_query_procperf(void) /* Find out the number of processors */ status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); NeededLength = sbi.NumberOfProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); sppi = HeapAlloc(GetProcessHeap(), 0, NeededLength); @@ -505,6 +517,7 @@ static void test_query_interrupt(void) /* Find out the number of processors */ status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); NeededLength = sbi.NumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION); sii = HeapAlloc(GetProcessHeap(), 0, NeededLength); @@ -918,6 +931,174 @@ static void test_query_process_image_file_name(void) HeapFree(GetProcessHeap(), 0, file_nameA); } +static void test_query_process_debug_object_handle(int argc, char **argv) +{ + char cmdline[MAX_PATH]; + STARTUPINFO si = {0}; + PROCESS_INFORMATION pi; + BOOL ret; + HANDLE debug_object; + NTSTATUS status; + + 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); + ok(ret, "CreateProcess failed with last error %u\n", GetLastError()); + if (!ret) return; + + status = pNtQueryInformationProcess(NULL, ProcessDebugObjectHandle, NULL, + 0, NULL); + if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED) + { + win_skip("ProcessDebugObjectHandle is not supported\n"); + return; + } + ok(status == STATUS_INFO_LENGTH_MISMATCH, + "Expected NtQueryInformationProcess to return STATUS_INFO_LENGTH_MISMATCH, got 0x%08x\n", + status); + + status = pNtQueryInformationProcess(NULL, ProcessDebugObjectHandle, NULL, + sizeof(debug_object), NULL); + ok(status == STATUS_INVALID_HANDLE || + status == STATUS_ACCESS_VIOLATION, /* XP */ + "Expected NtQueryInformationProcess to return STATUS_INVALID_HANDLE, got 0x%08x\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), + ProcessDebugObjectHandle, NULL, sizeof(debug_object), NULL); + ok(status == STATUS_ACCESS_VIOLATION, + "Expected NtQueryInformationProcess to return STATUS_ACCESS_VIOLATION, got 0x%08x\n", status); + + status = pNtQueryInformationProcess(NULL, ProcessDebugObjectHandle, + &debug_object, sizeof(debug_object), NULL); + ok(status == STATUS_INVALID_HANDLE, + "Expected NtQueryInformationProcess to return STATUS_ACCESS_VIOLATION, got 0x%08x\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), + ProcessDebugObjectHandle, &debug_object, + sizeof(debug_object) - 1, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH, + "Expected NtQueryInformationProcess to return STATUS_INFO_LENGTH_MISMATCH, got 0x%08x\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), + ProcessDebugObjectHandle, &debug_object, + sizeof(debug_object) + 1, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH, + "Expected NtQueryInformationProcess to return STATUS_INFO_LENGTH_MISMATCH, got 0x%08x\n", status); + + debug_object = (HANDLE)0xdeadbeef; + status = pNtQueryInformationProcess(GetCurrentProcess(), + ProcessDebugObjectHandle, &debug_object, + sizeof(debug_object), NULL); + ok(status == STATUS_PORT_NOT_SET, + "Expected NtQueryInformationProcess to return STATUS_PORT_NOT_SET, got 0x%08x\n", status); + ok(debug_object == NULL || + broken(debug_object == (HANDLE)0xdeadbeef), /* Wow64 */ + "Expected debug object handle to be NULL, got %p\n", debug_object); + + debug_object = (HANDLE)0xdeadbeef; + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugObjectHandle, + &debug_object, sizeof(debug_object), NULL); + todo_wine + ok(status == STATUS_SUCCESS, + "Expected NtQueryInformationProcess to return STATUS_SUCCESS, got 0x%08x\n", status); + todo_wine + ok(debug_object != NULL, + "Expected debug object handle to be non-NULL, got %p\n", debug_object); + + for (;;) + { + DEBUG_EVENT ev; + + ret = WaitForDebugEvent(&ev, INFINITE); + ok(ret, "WaitForDebugEvent failed with last error %u\n", GetLastError()); + if (!ret) break; + + if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + + ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed with last error %u\n", GetLastError()); + if (!ret) break; + } + + ret = CloseHandle(pi.hThread); + ok(ret, "CloseHandle failed with last error %u\n", GetLastError()); + ret = CloseHandle(pi.hProcess); + ok(ret, "CloseHandle failed with last error %u\n", GetLastError()); +} + +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 }; + 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); + ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); + if (!ret) return; + + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, + NULL, 0, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status); + + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, + NULL, sizeof(debug_flags), NULL); + ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION || broken(status == STATUS_INVALID_INFO_CLASS) /* W7PROX64 (32-bit) */, + "Expected STATUS_INVALID_HANDLE, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + NULL, sizeof(debug_flags), NULL); + ok(status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + &debug_flags, sizeof(debug_flags) - 1, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + &debug_flags, sizeof(debug_flags) + 1, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == TRUE|| broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected flag TRUE, got %x.\n", debug_flags); + + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == FALSE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected flag FALSE, got %x.\n", debug_flags); + + for (;;) + { + DEBUG_EVENT ev; + + ret = WaitForDebugEvent(&ev, INFINITE); + ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); + if (!ret) break; + + if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + + ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); + if (!ret) break; + } + + ret = CloseHandle(pi.hThread); + ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); + ret = CloseHandle(pi.hProcess); + ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); +} static void test_readvirtualmemory(void) { @@ -970,6 +1151,153 @@ static void test_readvirtualmemory(void) CloseHandle(process); } +static void test_mapprotection(void) +{ + HANDLE h; + void* addr; + MEMORY_BASIC_INFORMATION info; + ULONG oldflags, flagsize, flags = MEM_EXECUTE_OPTION_ENABLE; + LARGE_INTEGER size, offset; + NTSTATUS status; + SIZE_T retlen, count; + void (*f)(void); + + if (!pNtClose) { + skip("No NtClose ... Win98\n"); + return; + } + /* Switch to being a noexec unaware process */ + status = pNtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &oldflags, sizeof (oldflags), &flagsize); + if (status == STATUS_INVALID_PARAMETER) { + skip("Invalid Parameter on ProcessExecuteFlags query?\n"); + return; + } + ok( (status == STATUS_SUCCESS) || (status == STATUS_INVALID_INFO_CLASS), "Expected STATUS_SUCCESS, got %08x\n", status); + status = pNtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) ); + ok( (status == STATUS_SUCCESS) || (status == STATUS_INVALID_INFO_CLASS), "Expected STATUS_SUCCESS, got %08x\n", status); + + size.u.LowPart = 0x1000; + size.u.HighPart = 0; + status = pNtCreateSection ( &h, + STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, + NULL, + &size, + PAGE_READWRITE, + SEC_COMMIT | SEC_NOCACHE, + 0 + ); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + + offset.u.LowPart = 0; + offset.u.HighPart = 0; + count = 0x1000; + 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 */ + 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); + ok( retlen == sizeof(info), "Expected STATUS_SUCCESS, got %08x\n", status); + ok(info.Protect == PAGE_READWRITE, "addr.Protect is not PAGE_READWRITE, but 0x%x\n", info.Protect); + + status = pNtUnmapViewOfSection (GetCurrentProcess(), addr); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + pNtClose (h); + + /* Switch back */ + pNtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &oldflags, sizeof(oldflags) ); +} + +static void test_queryvirtualmemory(void) +{ + NTSTATUS status; + SIZE_T readcount; + static const char teststring[] = "test string"; + static char datatestbuf[42] = "abc"; + static char rwtestbuf[42]; + MEMORY_BASIC_INFORMATION mbi; + char stackbuf[42]; + HMODULE module; + + module = GetModuleHandle( "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); + ok( readcount == sizeof(MEMORY_BASIC_INFORMATION), "Expected to read %d bytes, got %ld\n",(int)sizeof(MEMORY_BASIC_INFORMATION),readcount); + ok (mbi.AllocationBase == module, "mbi.AllocationBase is 0x%p, expected 0x%p\n", mbi.AllocationBase, module); + ok (mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "mbi.AllocationProtect is 0x%x, expected 0x%x\n", mbi.AllocationProtect, PAGE_EXECUTE_WRITECOPY); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%x\n", mbi.State, MEM_COMMIT); + ok (mbi.Protect == PAGE_READONLY, "mbi.Protect is 0x%x, expected 0x%x\n", mbi.Protect, PAGE_READONLY); + 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" ); + 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); + ok (mbi.AllocationBase == module, "mbi.AllocationBase is 0x%p, expected 0x%p\n", mbi.AllocationBase, module); + ok (mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "mbi.AllocationProtect is 0x%x, expected 0x%x\n", mbi.AllocationProtect, PAGE_EXECUTE_WRITECOPY); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%x\n", mbi.State, MEM_COMMIT); + ok (mbi.Protect == PAGE_EXECUTE_READ, "mbi.Protect is 0x%x, expected 0x%x\n", mbi.Protect, PAGE_EXECUTE_READ); + + trace("Check flags of heap at %p\n", GetProcessHeap()); + status = pNtQueryVirtualMemory(NtCurrentProcess(), GetProcessHeap(), 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); + ok (mbi.AllocationProtect == PAGE_READWRITE || mbi.AllocationProtect == PAGE_EXECUTE_READWRITE, + "mbi.AllocationProtect is 0x%x\n", mbi.AllocationProtect); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%x\n", mbi.State, MEM_COMMIT); + ok (mbi.Protect == PAGE_READWRITE || mbi.Protect == PAGE_EXECUTE_READWRITE, + "mbi.Protect is 0x%x\n", mbi.Protect); + + trace("Check flags of stack at %p\n", stackbuf); + status = pNtQueryVirtualMemory(NtCurrentProcess(), stackbuf, 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); + ok (mbi.AllocationProtect == PAGE_READWRITE, "mbi.AllocationProtect is 0x%x, expected 0x%x\n", mbi.AllocationProtect, PAGE_READWRITE); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%x\n", mbi.State, MEM_COMMIT); + 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 ); + 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); + ok (mbi.AllocationBase == module, "mbi.AllocationBase is 0x%p, expected 0x%p\n", mbi.AllocationBase, module); + ok (mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "mbi.AllocationProtect is 0x%x, expected 0x%x\n", mbi.AllocationProtect, PAGE_EXECUTE_WRITECOPY); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%X\n", mbi.State, MEM_COMMIT); + if (mbi.Protect != PAGE_READONLY) + todo_wine ok( mbi.Protect == PAGE_READONLY, "mbi.Protect is 0x%x, expected 0x%X\n", mbi.Protect, PAGE_READONLY); + + trace("Check flags of read-write data at %p\n", datatestbuf); + status = pNtQueryVirtualMemory(NtCurrentProcess(), datatestbuf, 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); + ok (mbi.AllocationBase == module, "mbi.AllocationBase is 0x%p, expected 0x%p\n", mbi.AllocationBase, module); + ok (mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "mbi.AllocationProtect is 0x%x, expected 0x%x\n", mbi.AllocationProtect, PAGE_EXECUTE_WRITECOPY); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%X\n", mbi.State, MEM_COMMIT); + ok (mbi.Protect == PAGE_READWRITE || mbi.Protect == PAGE_WRITECOPY, + "mbi.Protect is 0x%x\n", mbi.Protect); + + trace("Check flags of read-write uninitialized data (.bss) at %p\n", rwtestbuf); + status = pNtQueryVirtualMemory(NtCurrentProcess(), rwtestbuf, 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); + if (mbi.AllocationBase == module) + { + ok (mbi.AllocationProtect == PAGE_EXECUTE_WRITECOPY, "mbi.AllocationProtect is 0x%x, expected 0x%x\n", mbi.AllocationProtect, PAGE_EXECUTE_WRITECOPY); + ok (mbi.State == MEM_COMMIT, "mbi.State is 0x%x, expected 0x%X\n", mbi.State, MEM_COMMIT); + ok (mbi.Protect == PAGE_READWRITE, "mbi.Protect is 0x%x, expected 0x%X\n", mbi.Protect, PAGE_READWRITE); + } + else skip( "bss is outside of module\n" ); /* this can happen on Mac OS */ +} + static void test_affinity(void) { NTSTATUS status; @@ -1009,6 +1337,7 @@ static void test_affinity(void) status = pNtSetInformationThread( GetCurrentThread(), ThreadAffinityMask, &thread_affinity, sizeof(thread_affinity) ); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( tbi.AffinityMask == 1, "Unexpected thread affinity\n" ); /* NOTE: Pre-Vista does not recognize the "all processors" flag (all bits set) */ @@ -1027,6 +1356,7 @@ static void test_affinity(void) if (status == STATUS_SUCCESS) { status = pNtQueryInformationThread( GetCurrentThread(), ThreadBasicInformation, &tbi, sizeof(tbi), NULL ); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( broken(tbi.AffinityMask == 1) || tbi.AffinityMask == (1 << si.dwNumberOfProcessors) - 1, "Unexpected thread affinity\n" ); } @@ -1147,14 +1477,28 @@ START_TEST(info) trace("Starting test_query_process_handlecount()\n"); test_query_process_handlecount(); - /* 27 ProcessImageFileName */ + /* 0x1B ProcessImageFileName */ trace("Starting test_query_process_image_file_name()\n"); test_query_process_image_file_name(); + /* 0x1E ProcessDebugObjectHandle */ + trace("Starting test_query_process_debug_object_handle()\n"); + test_query_process_debug_object_handle(argc, argv); + + /* 0x1F ProcessDebugFlags */ + trace("Starting test_process_debug_flags()\n"); + test_query_process_debug_flags(argc, argv); + /* belongs into it's own file */ trace("Starting test_readvirtualmemory()\n"); test_readvirtualmemory(); + trace("Starting test_queryvirtualmemory()\n"); + test_queryvirtualmemory(); + + trace("Starting test_mapprotection()\n"); + test_mapprotection(); + trace("Starting test_affinity()\n"); test_affinity(); } diff --git a/rostests/winetests/ntdll/large_int.c b/rostests/winetests/ntdll/large_int.c index 69de5b78947..f13ae882d05 100755 --- a/rostests/winetests/ntdll/large_int.c +++ b/rostests/winetests/ntdll/large_int.c @@ -326,7 +326,7 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t /* the string would have (which can be larger than the MaximumLength). */ /* To allow all this in the tests we do the following: */ if (expected_unicode_string.Length >= 64) { - /* The value is too large to convert only triggerd when testing native */ + /* The value is too large to convert only triggered when testing native */ /* Length is not filled with the expected string length (garbage?) */ expected_unicode_string.Length = unicode_string.Length; } /* if */ diff --git a/rostests/winetests/ntdll/ntdll.rbuild b/rostests/winetests/ntdll/ntdll.rbuild index 58c32adc1b5..6ab283d8d7d 100644 --- a/rostests/winetests/ntdll/ntdll.rbuild +++ b/rostests/winetests/ntdll/ntdll.rbuild @@ -17,6 +17,7 @@ large_int.c om.c path.c + pipe.c port.c reg.c rtlbitmap.c diff --git a/rostests/winetests/ntdll/om.c b/rostests/winetests/ntdll/om.c index 24339bb593e..ac377616446 100644 --- a/rostests/winetests/ntdll/om.c +++ b/rostests/winetests/ntdll/om.c @@ -46,6 +46,7 @@ static NTSTATUS (WINAPI *pNtOpenSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJEC static NTSTATUS (WINAPI *pNtCreateSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING); static NTSTATUS (WINAPI *pNtQuerySymbolicLinkObject)(HANDLE,PUNICODE_STRING,PULONG); static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG); +static NTSTATUS (WINAPI *pNtReleaseSemaphore)(HANDLE handle, ULONG count, PULONG previous); static void test_case_sensitive (void) @@ -419,9 +420,12 @@ static void test_directory(void) memset( buffer, 0xaa, sizeof(buffer) ); status = pNtQuerySymbolicLinkObject( dir, &str, &len ); ok( status == STATUS_SUCCESS, "NtQuerySymbolicLinkObject failed %08x\n", status ); + if (status != STATUS_SUCCESS) + goto error; full_len = str.Length + sizeof(WCHAR); ok( len == full_len, "bad length %u/%u\n", len, full_len ); - ok( buffer[len / sizeof(WCHAR) - 1] == 0, "no terminating null\n" ); + if (len == full_len) + ok( buffer[len / sizeof(WCHAR) - 1] == 0, "no terminating null\n" ); str.MaximumLength = str.Length; len = 0xdeadbeef; @@ -441,6 +445,7 @@ static void test_directory(void) ok( status == STATUS_SUCCESS, "NtQuerySymbolicLinkObject failed %08x\n", status ); ok( len == full_len, "bad length %u/%u\n", len, full_len ); +error: pNtClose(dir); } @@ -654,10 +659,12 @@ static void test_query_object(void) { static const WCHAR name[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s', '\\','t','e','s','t','_','e','v','e','n','t'}; + static const WCHAR type_event[] = {'E','v','e','n','t'}; + static const WCHAR type_file[] = {'F','i','l','e'}; HANDLE handle; char buffer[1024]; NTSTATUS status; - ULONG len; + ULONG len, expected_len; UNICODE_STRING *str; char dir[MAX_PATH]; @@ -668,11 +675,21 @@ static void test_query_object(void) ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + len = 0; + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, 0, &len ); + todo_wine ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + todo_wine ok( len >= sizeof(OBJECT_TYPE_INFORMATION) + sizeof(type_event) + sizeof(WCHAR), "unexpected len %u\n", len ); + len = 0; status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(UNICODE_STRING), &len ); ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + len = 0; + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(OBJECT_TYPE_INFORMATION), &len ); + todo_wine ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + todo_wine ok( len >= sizeof(OBJECT_TYPE_INFORMATION) + sizeof(type_event) + sizeof(WCHAR), "unexpected len %u\n", len ); + len = 0; status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); @@ -689,6 +706,21 @@ static void test_query_object(void) ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + len = 0; + memset( buffer, 0, sizeof(buffer) ); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(buffer), &len ); + todo_wine ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + todo_wine ok( len > sizeof(OBJECT_TYPE_INFORMATION), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + todo_wine ok( len >= sizeof(OBJECT_TYPE_INFORMATION) + str->Length + sizeof(WCHAR), "unexpected len %u\n", len ); + todo_wine ok( str->Buffer && !memcmp( str->Buffer, type_event, sizeof(type_file) ), + "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); + + len -= sizeof(WCHAR); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, len, &len ); + todo_wine ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + todo_wine ok( len >= sizeof(OBJECT_TYPE_INFORMATION) + sizeof(type_event) + sizeof(WCHAR), "unexpected len %u\n", len ); + pNtClose( handle ); handle = CreateEventA( NULL, FALSE, FALSE, NULL ); @@ -709,13 +741,62 @@ static void test_query_object(void) ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); str = (UNICODE_STRING *)buffer; - ok( sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR) == len || - broken(sizeof(UNICODE_STRING) + str->Length == len), /* NT4 */ + expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR); + ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */ "unexpected len %u\n", len ); trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, 0, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INSUFFICIENT_RESOURCES), + "NtQueryObject failed %x\n", status ); + ok( len == expected_len || broken(!len || len == sizeof(UNICODE_STRING)), + "unexpected len %u\n", len ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(UNICODE_STRING), &len ); + ok( status == STATUS_BUFFER_OVERFLOW || broken(status == STATUS_INSUFFICIENT_RESOURCES + || status == STATUS_INFO_LENGTH_MISMATCH), + "NtQueryObject failed %x\n", status ); + ok( len == expected_len || broken(!len), + "unexpected len %u\n", len ); + + len = 0; + memset( buffer, 0, sizeof(buffer) ); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(buffer), &len ); + todo_wine ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + todo_wine ok( len > sizeof(OBJECT_TYPE_INFORMATION), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(OBJECT_TYPE_INFORMATION) + str->Length + sizeof(WCHAR); + todo_wine ok( len >= expected_len, "unexpected len %u\n", len ); + todo_wine ok( str->Buffer && !memcmp( str->Buffer, type_file, sizeof(type_file) ), + "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); + pNtClose( handle ); } +static void test_type_mismatch(void) +{ + HANDLE h; + NTSTATUS res; + OBJECT_ATTRIBUTES attr; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = NULL; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + res = pNtCreateEvent( &h, 0, &attr, 0, 0 ); + ok(!res, "can't create event: %x\n", res); + + res = pNtReleaseSemaphore( h, 30, NULL ); + ok(res == STATUS_OBJECT_TYPE_MISMATCH, "expected 0xc0000024, got %x\n", res); + + pNtClose( h ); +} + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -747,6 +828,7 @@ START_TEST(om) pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer"); pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection"); pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject"); + pNtReleaseSemaphore = (void *)GetProcAddress(hntdll, "NtReleaseSemaphore"); test_case_sensitive(); test_namespace_pipe(); @@ -754,4 +836,5 @@ START_TEST(om) test_directory(); test_symboliclink(); test_query_object(); + test_type_mismatch(); } diff --git a/rostests/winetests/ntdll/pipe.c b/rostests/winetests/ntdll/pipe.c new file mode 100644 index 00000000000..8f7bd8fe51f --- /dev/null +++ b/rostests/winetests/ntdll/pipe.c @@ -0,0 +1,430 @@ +/* Unit test suite for Ntdll NamedPipe API functions + * + * Copyright 2011 Bernhard Loos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winnls.h" +#include "wine/test.h" +#include "winternl.h" +#include "winioctl.h" + +#ifndef __WINE_WINTERNL_H + +typedef struct { + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION; + +#ifndef FILE_SYNCHRONOUS_IO_ALERT +#define FILE_SYNCHRONOUS_IO_ALERT 0x10 +#endif + +#ifndef FILE_SYNCHRONOUS_IO_NONALERT +#define FILE_SYNCHRONOUS_IO_NONALERT 0x20 +#endif + +#ifndef FSCTL_PIPE_LISTEN +#define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif +#endif + +static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code, PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size); +static NTSTATUS (WINAPI *pNtCreateNamedPipeFile) (PHANDLE handle, ULONG access, + POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb, + ULONG sharing, ULONG dispo, ULONG options, + ULONG pipe_type, ULONG read_mode, + ULONG completion_mode, ULONG max_inst, + ULONG inbound_quota, ULONG outbound_quota, + PLARGE_INTEGER timeout); +static NTSTATUS (WINAPI *pNtQueryInformationFile) (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass); +static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status); +static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source); + +static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId); +static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData); + + +static BOOL init_func_ptrs(void) +{ + HMODULE module = GetModuleHandle("ntdll.dll"); + +#define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \ + trace("GetProcAddress(%s) failed\n", #name); \ + return FALSE; \ + } + + loadfunc(NtFsControlFile) + loadfunc(NtCreateNamedPipeFile) + loadfunc(NtQueryInformationFile) + loadfunc(NtCancelIoFile) + loadfunc(RtlInitUnicodeString) + + /* not fatal */ + module = GetModuleHandle("kernel32.dll"); + pOpenThread = (void *)GetProcAddress(module, "OpenThread"); + pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC"); + return TRUE; +} + +static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\', + 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 }; +static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\', + 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 }; + +static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options) +{ + IO_STATUS_BLOCK iosb; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING name; + LARGE_INTEGER timeout; + NTSTATUS res; + + pRtlInitUnicodeString(&name, testpipe_nt); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &name; + attr.Attributes = 0x40; /*case insensitive */ + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + timeout.QuadPart = -100000000000ll; + + res = pNtCreateNamedPipeFile(handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, sharing, 2 /*FILE_CREATE*/, + options, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); + return res; +} + +static void test_create_invalid(void) +{ + IO_STATUS_BLOCK iosb; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING name; + LARGE_INTEGER timeout; + NTSTATUS res; + HANDLE handle, handle2; + FILE_PIPE_LOCAL_INFORMATION info; + + pRtlInitUnicodeString(&name, testpipe_nt); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &name; + attr.Attributes = 0x40; /*case insensitive */ + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + timeout.QuadPart = -100000000000ll; + +/* create a pipe with sharing = 0 */ + res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/, + 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); + todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res); + if (!res) + CloseHandle(handle); + +/* create a pipe without r/w access */ + res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/, + 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); + ok(!res, "NtCreateNamedPipeFile returned %x\n", res); + + res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24); + todo_wine ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res); + +/* test FILE_CREATE creation disposition */ + res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/, + 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); + todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res); + if (!res) + CloseHandle(handle2); + + CloseHandle(handle); +} + +static BOOL ioapc_called; +static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved) +{ + ioapc_called = TRUE; +} + +static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc) +{ + int dummy; + + ioapc_called = FALSE; + + return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0); +} + +static void test_overlapped(void) +{ + IO_STATUS_BLOCK iosb; + HANDLE hEvent; + HANDLE hPipe; + HANDLE hClient; + NTSTATUS res; + + hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError()); + + res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */); + ok(!res, "NtCreateNamedPipeFile returned %x\n", res); + + memset(&iosb, 0x55, sizeof(iosb)); + +/* try with event and apc */ + res = listen_pipe(hPipe, hEvent, &iosb, TRUE); + ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res); + + hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError()); + + ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status); + ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n"); + + ok(!ioapc_called, "IOAPC ran too early\n"); + + SleepEx(0, TRUE); /* alertable wait state */ + + ok(ioapc_called, "IOAPC didn't run\n"); + + CloseHandle(hEvent); + CloseHandle(hPipe); + CloseHandle(hClient); +} + +static BOOL userapc_called; +static void CALLBACK userapc(ULONG_PTR dwParam) +{ + userapc_called = TRUE; +} + +static BOOL open_succeeded; +static DWORD WINAPI thread(PVOID main_thread) +{ + HANDLE h; + + Sleep(400); + + if (main_thread) { + userapc_called = FALSE; + ok(pQueueUserAPC(&userapc, main_thread, 0), "can't queue user apc, GetLastError: %x\n", GetLastError()); + CloseHandle(main_thread); + } + + Sleep(400); + + h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); + + if (h != INVALID_HANDLE_VALUE) { + open_succeeded = TRUE; + Sleep(100); + CloseHandle(h); + } else + open_succeeded = FALSE; + + return 0; +} + +static void test_alertable(void) +{ + IO_STATUS_BLOCK iosb; + HANDLE hEvent; + HANDLE hPipe; + NTSTATUS res; + HANDLE hThread; + + memset(&iosb, 0x55, sizeof(iosb)); + + hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError()); + + res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT); + ok(!res, "NtCreateNamedPipeFile returned %x\n", res); + +/* queue an user apc before calling listen */ + userapc_called = FALSE; + ok(pQueueUserAPC(&userapc, GetCurrentThread(), 0), "can't queue user apc, GetLastError: %x\n", GetLastError()); + + res = listen_pipe(hPipe, hEvent, &iosb, TRUE); + todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res); + + todo_wine ok(userapc_called, "user apc didn't run\n"); + ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status); + todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n"); + ok(!ioapc_called, "IOAPC ran\n"); + +/* queue an user apc from a different thread */ + hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0); + ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError()); + + /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state + instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */ + res = listen_pipe(hPipe, hEvent, &iosb, TRUE); + todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res); + + ok(userapc_called, "user apc didn't run\n"); + todo_wine ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status); + ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n"); + ok(!ioapc_called, "IOAPC ran\n"); + + WaitForSingleObject(hThread, INFINITE); + + SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */ + + ok(open_succeeded, "couldn't open client side pipe\n"); + + CloseHandle(hThread); + DisconnectNamedPipe(hPipe); + +/* finally try without an apc */ + hThread = CreateThread(NULL, 0, &thread, 0, 0, 0); + ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError()); + + res = listen_pipe(hPipe, hEvent, &iosb, TRUE); + todo_wine ok(!res, "NtFsControlFile returned %x\n", res); + + ok(open_succeeded, "couldn't open client side pipe\n"); + ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status); + todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n"); + + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + CloseHandle(hEvent); + CloseHandle(hPipe); +} + +static void test_nonalertable(void) +{ + IO_STATUS_BLOCK iosb; + HANDLE hEvent; + HANDLE hPipe; + NTSTATUS res; + HANDLE hThread; + + memset(&iosb, 0x55, sizeof(iosb)); + + hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError()); + + res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); + ok(!res, "NtCreateNamedPipeFile returned %x\n", res); + + hThread = CreateThread(NULL, 0, &thread, 0, 0, 0); + ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError()); + + userapc_called = FALSE; + ok(pQueueUserAPC(&userapc, GetCurrentThread(), 0), "can't queue user apc, GetLastError: %x\n", GetLastError()); + + res = listen_pipe(hPipe, hEvent, &iosb, TRUE); + todo_wine ok(!res, "NtFsControlFile returned %x\n", res); + + ok(open_succeeded, "couldn't open client side pipe\n"); + todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status); + todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n"); + + ok(!ioapc_called, "IOAPC ran too early\n"); + ok(!userapc_called, "user apc ran too early\n"); + + SleepEx(0, TRUE); /* alertable wait state */ + + ok(ioapc_called, "IOAPC didn't run\n"); + ok(userapc_called, "user apc didn't run\n"); + + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + CloseHandle(hEvent); + CloseHandle(hPipe); +} + +static void test_cancelio(void) +{ + IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK cancel_sb; + HANDLE hEvent; + HANDLE hPipe; + NTSTATUS res; + + hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError()); + + res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */); + ok(!res, "NtCreateNamedPipeFile returned %x\n", res); + + memset(&iosb, 0x55, sizeof(iosb)); + + res = listen_pipe(hPipe, hEvent, &iosb, TRUE); + ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res); + + res = pNtCancelIoFile(hPipe, &cancel_sb); + todo_wine ok(!res, "NtCancelIoFile returned %x\n", res); + + todo_wine { + ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status); + ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n"); + } + + ok(!ioapc_called, "IOAPC ran too early\n"); + + SleepEx(0, TRUE); /* alertable wait state */ + + ok(ioapc_called, "IOAPC didn't run\n"); + + CloseHandle(hEvent); + CloseHandle(hPipe); +} + +START_TEST(pipe) +{ + if (!init_func_ptrs()) + return; + + trace("starting invalid create tests\n"); + test_create_invalid(); + + trace("starting overlapped tests\n"); + test_overlapped(); + + if (!pOpenThread || !pQueueUserAPC) + return; + + trace("starting alertable tests\n"); + test_alertable(); + + trace("starting nonalertable tests\n"); + test_nonalertable(); + + trace("starting cancelio tests\n"); + test_cancelio(); +} diff --git a/rostests/winetests/ntdll/port.c b/rostests/winetests/ntdll/port.c index d092ed789ab..20e5831b5db 100644 --- a/rostests/winetests/ntdll/port.c +++ b/rostests/winetests/ntdll/port.c @@ -128,7 +128,6 @@ static NTSTATUS (WINAPI *pNtConnectPort)(PHANDLE,PUNICODE_STRING, PLPC_SECTION_WRITE,PLPC_SECTION_READ, PVOID,PVOID,PULONG); static NTSTATUS (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR); -static NTSTATUS (WINAPI *pNtWaitForSingleObject)(HANDLE,BOOLEAN,PLARGE_INTEGER); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static BOOL is_wow64; @@ -150,7 +149,6 @@ static BOOL init_function_ptrs(void) pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort"); pNtConnectPort = (void *)GetProcAddress(hntdll, "NtConnectPort"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); - pNtWaitForSingleObject = (void *)GetProcAddress(hntdll, "NtWaitForSingleObject"); if (!pNtCompleteConnectPort || !pNtAcceptConnectPort || !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort || diff --git a/rostests/winetests/ntdll/reg.c b/rostests/winetests/ntdll/reg.c index 1cad29e9829..5ca14eb4192 100755 --- a/rostests/winetests/ntdll/reg.c +++ b/rostests/winetests/ntdll/reg.c @@ -637,6 +637,7 @@ static void test_NtDeleteKey(void) InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&hkey, am, &attr); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); status = pNtDeleteKey(hkey); ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status); @@ -1197,6 +1198,11 @@ static void test_redirection(void) pRtlInitUnicodeString( &str, classes64W ); status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + if (status == STATUS_ACCESS_DENIED) + { + skip("Not authorized to modify the Classes key\n"); + return; + } ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status ); pRtlInitUnicodeString( &str, classes32W ); diff --git a/rostests/winetests/ntdll/rtl.c b/rostests/winetests/ntdll/rtl.c index 6e76a3cc58d..63bc813f282 100755 --- a/rostests/winetests/ntdll/rtl.c +++ b/rostests/winetests/ntdll/rtl.c @@ -24,6 +24,7 @@ #include #include "ntdll_test.h" +#include "inaddr.h" #ifndef __WINE_WINTERNL_H @@ -45,6 +46,20 @@ typedef struct _RTL_HANDLE_TABLE #endif +/* avoid #include */ +#undef htons +#ifdef WORDS_BIGENDIAN +#define htons(s) ((USHORT)(s)) +#else /* WORDS_BIGENDIAN */ +static inline USHORT __my_ushort_swap(USHORT s) +{ + return (s >> 8) | (s << 8); +} +#define htons(s) __my_ushort_swap(s) +#endif /* WORDS_BIGENDIAN */ + + + /* Function ptrs for ntdll calls */ static HMODULE hntdll = 0; static SIZE_T (WINAPI *pRtlCompareMemory)(LPCVOID,LPCVOID,SIZE_T); @@ -70,8 +85,14 @@ static NTSTATUS (WINAPI *pRtlFreeSid)(PSID); static struct _TEB * (WINAPI *pNtCurrentTeb)(void); static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD); +static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,USHORT*,INT_PTR); +static CHAR * (WINAPI *pRtlIpv4AddressToStringA)(const IN_ADDR *, LPSTR); +static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG); + static HMODULE hkernel32 = 0; static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); + + #define LEN 16 static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */ static ULONG src_aligned_block[4]; @@ -107,6 +128,9 @@ static void InitFunctionPtrs(void) pNtCurrentTeb = (void *)GetProcAddress(hntdll, "NtCurrentTeb"); pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode"); pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode"); + pLdrProcessRelocationBlock = (void *)GetProcAddress(hntdll, "LdrProcessRelocationBlock"); + pRtlIpv4AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringA"); + pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA"); } hkernel32 = LoadLibraryA("kernel32.dll"); ok(hkernel32 != 0, "LoadLibrary failed\n"); @@ -1006,8 +1030,8 @@ static void test_RtlAllocateAndInitializeSid(void) /* these tests crash on XP */ if (0) { - ret = pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); - ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL); + pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid); + pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL); } ret = pRtlAllocateAndInitializeSid(&sia, 9, 1, 2, 3, 4, 5, 6, 7, 8, &psid); @@ -1094,6 +1118,201 @@ static void test_RtlThreadErrorMode(void) pRtlSetThreadErrorMode(oldmode, NULL); } +static void test_LdrProcessRelocationBlock(void) +{ + IMAGE_BASE_RELOCATION *ret; + USHORT reloc; + DWORD addr32; + SHORT addr16; + + if(!pLdrProcessRelocationBlock) { + win_skip("LdrProcessRelocationBlock not available\n"); + return; + } + + addr32 = 0x50005; + reloc = IMAGE_REL_BASED_HIGHLOW<<12; + ret = pLdrProcessRelocationBlock(&addr32, 1, &reloc, 0x500050); + ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1); + ok(addr32 == 0x550055, "addr32 = %x, expected 0x550055\n", addr32); + + addr16 = 0x505; + reloc = IMAGE_REL_BASED_HIGH<<12; + ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060); + ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1); + ok(addr16 == 0x555, "addr16 = %x, expected 0x555\n", addr16); + + addr16 = 0x505; + reloc = IMAGE_REL_BASED_LOW<<12; + ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060); + ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1); + ok(addr16 == 0x565, "addr16 = %x, expected 0x565\n", addr16); +} + +static void test_RtlIpv4AddressToString(void) +{ + CHAR buffer[20]; + CHAR *res; + IN_ADDR ip; + DWORD len; + + if (!pRtlIpv4AddressToStringA) + { + win_skip("RtlIpv4AddressToStringA not available\n"); + return; + } + + ip.S_un.S_un_b.s_b1 = 1; + ip.S_un.S_un_b.s_b2 = 2; + ip.S_un.S_un_b.s_b3 = 3; + ip.S_un.S_un_b.s_b4 = 4; + + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringA(&ip, buffer); + len = strlen(buffer); + ok(res == (buffer + len), "got %p with '%s' (expected %p)\n", res, buffer, buffer + len); + + res = pRtlIpv4AddressToStringA(&ip, NULL); + ok( (res == (char *)~0) || + broken(res == (char *)0 + len), /* XP and w2003 */ + "got %p (expected ~0)\n", res); + + if (0) { + /* this crashes in windows */ + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringA(NULL, buffer); + trace("got %p with '%s'\n", res, buffer); + } + + if (0) { + /* this crashes in windows */ + res = pRtlIpv4AddressToStringA(NULL, NULL); + trace("got %p\n", res); + } +} + +static void test_RtlIpv4AddressToStringEx(void) +{ + CHAR ip_1234[] = "1.2.3.4"; + CHAR ip_1234_80[] = "1.2.3.4:80"; + LPSTR expect; + CHAR buffer[30]; + NTSTATUS res; + IN_ADDR ip; + ULONG size; + DWORD used; + USHORT port; + + if (!pRtlIpv4AddressToStringExA) + { + win_skip("RtlIpv4AddressToStringExA not available\n"); + return; + } + + ip.S_un.S_un_b.s_b1 = 1; + ip.S_un.S_un_b.s_b2 = 2; + ip.S_un.S_un_b.s_b3 = 3; + ip.S_un.S_un_b.s_b4 = 4; + + port = htons(80); + expect = ip_1234_80; + + size = sizeof(buffer); + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + used = strlen(buffer); + ok( (res == STATUS_SUCCESS) && + (size == strlen(expect) + 1) && !strcmp(buffer, expect), + "got 0x%x and size %d with '%s'\n", res, size, buffer); + + size = used + 1; + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + ok( (res == STATUS_SUCCESS) && + (size == strlen(expect) + 1) && !strcmp(buffer, expect), + "got 0x%x and size %d with '%s'\n", res, size, buffer); + + size = used; + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1), + "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n", + res, size, buffer, used + 1); + + size = used - 1; + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1), + "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n", + res, size, buffer, used + 1); + + + /* to get only the ip, use 0 as port */ + port = 0; + expect = ip_1234; + + size = sizeof(buffer); + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + used = strlen(buffer); + ok( (res == STATUS_SUCCESS) && + (size == strlen(expect) + 1) && !strcmp(buffer, expect), + "got 0x%x and size %d with '%s'\n", res, size, buffer); + + size = used + 1; + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + ok( (res == STATUS_SUCCESS) && + (size == strlen(expect) + 1) && !strcmp(buffer, expect), + "got 0x%x and size %d with '%s'\n", res, size, buffer); + + size = used; + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1), + "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n", + res, size, buffer, used + 1); + + size = used - 1; + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size); + ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1), + "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n", + res, size, buffer, used + 1); + + + /* parameters are checked */ + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(&ip, 0, buffer, NULL); + ok(res == STATUS_INVALID_PARAMETER, + "got 0x%x with '%s' (expected STATUS_INVALID_PARAMETER)\n", res, buffer); + + size = sizeof(buffer); + res = pRtlIpv4AddressToStringExA(&ip, 0, NULL, &size); + ok( res == STATUS_INVALID_PARAMETER, + "got 0x%x and size %d (expected STATUS_INVALID_PARAMETER)\n", res, size); + + size = sizeof(buffer); + memset(buffer, '#', sizeof(buffer) - 1); + buffer[sizeof(buffer) -1] = 0; + res = pRtlIpv4AddressToStringExA(NULL, 0, buffer, &size); + ok( res == STATUS_INVALID_PARAMETER, + "got 0x%x and size %d with '%s' (expected STATUS_INVALID_PARAMETER)\n", + res, size, buffer); +} + + START_TEST(rtl) { InitFunctionPtrs(); @@ -1114,4 +1333,7 @@ START_TEST(rtl) test_RtlAllocateAndInitializeSid(); test_RtlDeleteTimer(); test_RtlThreadErrorMode(); + test_LdrProcessRelocationBlock(); + test_RtlIpv4AddressToString(); + test_RtlIpv4AddressToStringEx(); } diff --git a/rostests/winetests/ntdll/rtlbitmap.c b/rostests/winetests/ntdll/rtlbitmap.c index d24f0af8be6..4c1559b6012 100755 --- a/rostests/winetests/ntdll/rtlbitmap.c +++ b/rostests/winetests/ntdll/rtlbitmap.c @@ -497,6 +497,7 @@ static void test_RtlFindSetRuns(void) /* Get first 2 */ ulCount = pRtlFindSetRuns(&bm, runs, 2, FALSE); + ok(ulCount == 2, "RtlFindClearRuns returned %d, expected 2\n", ulCount); ok (runs[0].StartingIndex == 7 || runs[0].StartingIndex == 101,"bad find\n"); ok (runs[1].StartingIndex == 7 || runs[1].StartingIndex == 101,"bad find\n"); ok (runs[0].NumberOfBits + runs[1].NumberOfBits == 19 + 3,"bad size\n"); @@ -506,6 +507,7 @@ static void test_RtlFindSetRuns(void) /* Get longest 3 */ memset(runs, 0, sizeof(runs)); ulCount = pRtlFindSetRuns(&bm, runs, 2, TRUE); + ok(ulCount == 2, "RtlFindClearRuns returned %d, expected 2\n", ulCount); ok (runs[0].StartingIndex == 7 || runs[0].StartingIndex == 1877,"bad find\n"); ok (runs[1].StartingIndex == 7 || runs[1].StartingIndex == 1877,"bad find\n"); ok (runs[0].NumberOfBits + runs[1].NumberOfBits == 33 + 19,"bad size\n"); @@ -515,6 +517,7 @@ static void test_RtlFindSetRuns(void) /* Get all 3 */ memset(runs, 0, sizeof(runs)); ulCount = pRtlFindSetRuns(&bm, runs, 3, TRUE); + ok(ulCount == 3, "RtlFindClearRuns returned %d, expected 3\n", ulCount); ok (runs[0].StartingIndex == 7 || runs[0].StartingIndex == 101 || runs[0].StartingIndex == 1877,"bad find\n"); ok (runs[1].StartingIndex == 7 || runs[1].StartingIndex == 101 || @@ -571,6 +574,7 @@ static void test_RtlFindClearRuns(void) /* Get first 2 */ ulCount = pRtlFindClearRuns(&bm, runs, 2, FALSE); + ok(ulCount == 2, "RtlFindClearRuns returned %d, expected 2\n", ulCount); ok (runs[0].StartingIndex == 7 || runs[0].StartingIndex == 101,"bad find\n"); ok (runs[1].StartingIndex == 7 || runs[1].StartingIndex == 101,"bad find\n"); ok (runs[0].NumberOfBits + runs[1].NumberOfBits == 19 + 3,"bad size\n"); @@ -580,6 +584,7 @@ static void test_RtlFindClearRuns(void) /* Get longest 3 */ memset(runs, 0, sizeof(runs)); ulCount = pRtlFindClearRuns(&bm, runs, 2, TRUE); + ok(ulCount == 2, "RtlFindClearRuns returned %d, expected 2\n", ulCount); ok (runs[0].StartingIndex == 7 || runs[0].StartingIndex == 1877,"bad find\n"); ok (runs[1].StartingIndex == 7 || runs[1].StartingIndex == 1877,"bad find\n"); ok (runs[0].NumberOfBits + runs[1].NumberOfBits == 33 + 19,"bad size\n"); @@ -589,6 +594,7 @@ static void test_RtlFindClearRuns(void) /* Get all 3 */ memset(runs, 0, sizeof(runs)); ulCount = pRtlFindClearRuns(&bm, runs, 3, TRUE); + ok(ulCount == 3, "RtlFindClearRuns returned %d, expected 3\n", ulCount); ok (runs[0].StartingIndex == 7 || runs[0].StartingIndex == 101 || runs[0].StartingIndex == 1877,"bad find\n"); ok (runs[1].StartingIndex == 7 || runs[1].StartingIndex == 101 || diff --git a/rostests/winetests/ntdll/rtlstr.c b/rostests/winetests/ntdll/rtlstr.c index 5dd35008d5d..5205089d87e 100755 --- a/rostests/winetests/ntdll/rtlstr.c +++ b/rostests/winetests/ntdll/rtlstr.c @@ -748,7 +748,10 @@ static const ustr2astr_t ustr2astr[] = { { 8, 6, 12, "------------", 12, 12, 12, "abcdef", FALSE, 5, 6, 6, "abcde", STATUS_BUFFER_OVERFLOW}, { 8, 7, 12, "------------", 12, 12, 12, "abcdef", FALSE, 6, 7, 7, "abcdef", STATUS_SUCCESS}, { 8, 7, 12, "------------", 0, 12, 12, NULL, FALSE, 0, 7, 0, "", STATUS_SUCCESS}, +#if 0 + /* crashes on Japanese and Chinese XP */ { 0, 0, 12, NULL, 10, 10, 12, NULL, FALSE, 5, 0, 0, NULL, STATUS_BUFFER_OVERFLOW}, +#endif }; #define NB_USTR2ASTR (sizeof(ustr2astr)/sizeof(*ustr2astr)) @@ -1610,7 +1613,7 @@ static void one_RtlIntegerToUnicodeString_test(int test_num, const int2str_t *in /* the string would have (which can be larger than the MaximumLength). */ /* To allow all this in the tests we do the following: */ if (expected_unicode_string.Length > 32 && unicode_string.Length == 0) { - /* The value is too large to convert only triggerd when testing native */ + /* The value is too large to convert only triggered when testing native */ expected_unicode_string.Length = 0; } } else { @@ -1751,7 +1754,7 @@ static void test_RtlIsTextUnicode(void) /* build byte reversed unicode string with no control chars */ be_unicode_no_controls = HeapAlloc(GetProcessHeap(), 0, sizeof(unicode) + sizeof(WCHAR)); - ok(be_unicode_no_controls != NULL, "Expeced HeapAlloc to succeed.\n"); + ok(be_unicode_no_controls != NULL, "Expected HeapAlloc to succeed.\n"); be_unicode_no_controls[0] = 0xfffe; for (i = 0; i < sizeof(unicode_no_controls)/sizeof(unicode_no_controls[0]); i++) be_unicode_no_controls[i + 1] = (unicode_no_controls[i] >> 8) | ((unicode_no_controls[i] & 0xff) << 8); @@ -1827,7 +1830,7 @@ static const WCHAR szGuid[] = { '{','0','1','0','2','0','3','0','4','-', static const WCHAR szGuid2[] = { '{','0','1','0','2','0','3','0','4','-', '0','5','0','6','-' ,'0','7','0','8','-','0','9','0','A','-', '0','B','0','C','0','D','0','E','0','F','0','A',']','\0' }; -DEFINE_GUID(IID_Endianess, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B, +DEFINE_GUID(IID_Endianness, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x0A); static void test_RtlGUIDFromString(void) @@ -1841,7 +1844,7 @@ static void test_RtlGUIDFromString(void) ret = pRtlGUIDFromString(&str, &guid); ok(ret == 0, "expected ret=0, got 0x%0x\n", ret); - ok(memcmp(&guid, &IID_Endianess, sizeof(guid)) == 0, "Endianess broken\n"); + ok(IsEqualGUID(&guid, &IID_Endianness), "Endianness broken\n"); str.Length = str.MaximumLength = sizeof(szGuid2) - sizeof(WCHAR); str.Buffer = (LPWSTR)szGuid2; @@ -1858,9 +1861,9 @@ static void test_RtlStringFromGUID(void) str.Length = str.MaximumLength = 0; str.Buffer = NULL; - ret = pRtlStringFromGUID(&IID_Endianess, &str); + ret = pRtlStringFromGUID(&IID_Endianness, &str); ok(ret == 0, "expected ret=0, got 0x%0x\n", ret); - ok(str.Buffer && !lstrcmpiW(str.Buffer, szGuid), "Endianess broken\n"); + ok(str.Buffer && !lstrcmpiW(str.Buffer, szGuid), "Endianness broken\n"); pRtlFreeUnicodeString(&str); } diff --git a/rostests/winetests/ntdll/string.c b/rostests/winetests/ntdll/string.c index 3f7236a3dfe..9422d415280 100755 --- a/rostests/winetests/ntdll/string.c +++ b/rostests/winetests/ntdll/string.c @@ -51,8 +51,8 @@ static LPWSTR (WINAPIV *p_ultow)(ULONG, LPWSTR, INT); static LPWSTR (WINAPIV *p_i64tow)(LONGLONG, LPWSTR, INT); static LPWSTR (WINAPIV *p_ui64tow)(ULONGLONG, LPWSTR, INT); -static long (WINAPIV *pwcstol)(LPCWSTR, LPWSTR *, INT); -static ULONG (WINAPIV *pwcstoul)(LPCWSTR, LPWSTR *, INT); +static LPWSTR (__cdecl *p_wcslwr)(LPWSTR); +static LPWSTR (__cdecl *p_wcsupr)(LPWSTR); static LPWSTR (WINAPIV *p_wcschr)(LPCWSTR, WCHAR); static LPWSTR (WINAPIV *p_wcsrchr)(LPCWSTR, WCHAR); @@ -89,8 +89,8 @@ static void InitFunctionPtrs(void) p_i64tow = (void *)GetProcAddress(hntdll, "_i64tow"); p_ui64tow = (void *)GetProcAddress(hntdll, "_ui64tow"); - pwcstol = (void *)GetProcAddress(hntdll, "wcstol"); - pwcstoul = (void *)GetProcAddress(hntdll, "wcstoul"); + p_wcslwr = (void *)GetProcAddress(hntdll, "_wcslwr"); + p_wcsupr = (void *)GetProcAddress(hntdll, "_wcsupr"); p_wcschr= (void *)GetProcAddress(hntdll, "wcschr"); p_wcsrchr= (void *)GetProcAddress(hntdll, "wcsrchr"); @@ -1143,22 +1143,54 @@ static void test_wcsrchr(void) "wcsrchr should have returned NULL\n"); } -static __cdecl int intcomparefunc(const void *a, const void*b) +static void test_wcslwrupr(void) { - ok (a != b, "must never get the same pointer\n"); - return (*(int*)a) - (*(int*)b); + static WCHAR teststringW[] = {'a','b','r','a','c','a','d','a','b','r','a',0}; + static WCHAR emptyW[1] = {0}; + static const WCHAR constemptyW[1] = {0}; + + if (0) /* crashes on native */ + { + static const WCHAR conststringW[] = {'a','b','r','a','c','a','d','a','b','r','a',0}; + ok(p_wcslwr((LPWSTR)conststringW) == conststringW, "p_wcslwr returned different string\n"); + ok(p_wcsupr((LPWSTR)conststringW) == conststringW, "p_wcsupr returned different string\n"); + ok(p_wcslwr(NULL) == NULL, "p_wcslwr didn't returned NULL\n"); + ok(p_wcsupr(NULL) == NULL, "p_wcsupr didn't returned NULL\n"); + } + ok(p_wcslwr(teststringW) == teststringW, "p_wcslwr returned different string\n"); + ok(p_wcsupr(teststringW) == teststringW, "p_wcsupr returned different string\n"); + ok(p_wcslwr(emptyW) == emptyW, "p_wcslwr returned different string\n"); + ok(p_wcsupr(emptyW) == emptyW, "p_wcsupr returned different string\n"); + ok(p_wcslwr((LPWSTR)constemptyW) == constemptyW, "p_wcslwr returned different string\n"); + ok(p_wcsupr((LPWSTR)constemptyW) == constemptyW, "p_wcsupr returned different string\n"); } -static __cdecl int charcomparefunc(const void *a, const void*b) +static __cdecl int intcomparefunc(const void *a, const void *b) { - ok (a != b, "must never get the same pointer\n"); - return (*(char*)a) - (*(char*)b); + const int *p = a, *q = b; + + ok (a != b, "must never get the same pointer\n"); + + return *p - *q; } -static __cdecl int strcomparefunc(const void *a, const void*b) +static __cdecl int charcomparefunc(const void *a, const void *b) { - ok (a != b, "must never get the same pointer\n"); - return lstrcmpA(*(char**)a,*(char**)b); + const char *p = a, *q = b; + + ok (a != b, "must never get the same pointer\n"); + + return *p - *q; +} + +static __cdecl int strcomparefunc(const void *a, const void *b) +{ + const char * const *p = a; + const char * const *q = b; + + ok (a != b, "must never get the same pointer\n"); + + return lstrcmpA(*p, *q); } static void test_qsort(void) @@ -1175,6 +1207,27 @@ static void test_qsort(void) "." }; + p_qsort ((void*)arr, 0, sizeof(int), intcomparefunc); + ok(arr[0] == 23, "badly sorted, nmemb=0, arr[0] is %d\n", arr[0]); + ok(arr[1] == 42, "badly sorted, nmemb=0, arr[1] is %d\n", arr[1]); + ok(arr[2] == 8, "badly sorted, nmemb=0, arr[2] is %d\n", arr[2]); + ok(arr[3] == 4, "badly sorted, nmemb=0, arr[3] is %d\n", arr[3]); + ok(arr[4] == 16, "badly sorted, nmemb=0, arr[4] is %d\n", arr[4]); + + p_qsort ((void*)arr, 1, sizeof(int), intcomparefunc); + ok(arr[0] == 23, "badly sorted, nmemb=1, arr[0] is %d\n", arr[0]); + ok(arr[1] == 42, "badly sorted, nmemb=1, arr[1] is %d\n", arr[1]); + ok(arr[2] == 8, "badly sorted, nmemb=1, arr[2] is %d\n", arr[2]); + ok(arr[3] == 4, "badly sorted, nmemb=1, arr[3] is %d\n", arr[3]); + ok(arr[4] == 16, "badly sorted, nmemb=1, arr[4] is %d\n", arr[4]); + + p_qsort ((void*)arr, 5, 0, intcomparefunc); + ok(arr[0] == 23, "badly sorted, size=0, arr[0] is %d\n", arr[0]); + ok(arr[1] == 42, "badly sorted, size=0, arr[1] is %d\n", arr[1]); + ok(arr[2] == 8, "badly sorted, size=0, arr[2] is %d\n", arr[2]); + ok(arr[3] == 4, "badly sorted, size=0, arr[3] is %d\n", arr[3]); + ok(arr[4] == 16, "badly sorted, size=0, arr[4] is %d\n", arr[4]); + p_qsort ((void*)arr, 5, sizeof(int), intcomparefunc); ok(arr[0] == 4, "badly sorted, arr[0] is %d\n", arr[0]); ok(arr[1] == 8, "badly sorted, arr[1] is %d\n", arr[1]); @@ -1241,6 +1294,8 @@ START_TEST(string) test_wcschr(); if (p_wcsrchr) test_wcsrchr(); + if (p_wcslwr && p_wcsupr) + test_wcslwrupr(); if (patoi) test_atoi(); if (patol) diff --git a/rostests/winetests/ntdll/testlist.c b/rostests/winetests/ntdll/testlist.c index 4bccf1732a7..f9560629ba9 100644 --- a/rostests/winetests/ntdll/testlist.c +++ b/rostests/winetests/ntdll/testlist.c @@ -18,6 +18,7 @@ extern void func_info(void); extern void func_large_int(void); extern void func_om(void); extern void func_path(void); +extern void func_pipe(void); extern void func_port(void); extern void func_reg(void); extern void func_rtl(void); @@ -40,6 +41,7 @@ const struct test winetest_testlist[] = { "large_int", func_large_int }, { "om", func_om }, { "path", func_path }, + { "pipe", func_pipe }, { "port", func_port }, { "reg", func_reg }, { "rtl", func_rtl }, diff --git a/rostests/winetests/ntdll/time.c b/rostests/winetests/ntdll/time.c index 16530c4d651..ff80b841078 100755 --- a/rostests/winetests/ntdll/time.c +++ b/rostests/winetests/ntdll/time.c @@ -39,7 +39,7 @@ static inline int IsLeapYear(int Year) } /* start time of the tests */ -TIME_FIELDS tftest = {1889,12,31,23,59,59,0,0}; +static TIME_FIELDS tftest = {1889,12,31,23,59,59,0,0}; static void test_pRtlTimeToTimeFields(void) {