https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f7932ba2de71f0340daa18...
commit f7932ba2de71f0340daa18db32e083383b8e680b Author: Amine Khaldi amine.khaldi@reactos.org AuthorDate: Sat Oct 21 14:36:29 2017 +0100
[NTDLL_WINETEST] Sync with Wine Staging 2.16. CORE-13762 --- modules/rostests/winetests/ntdll/CMakeLists.txt | 3 +- modules/rostests/winetests/ntdll/directory.c | 590 ++++++- modules/rostests/winetests/ntdll/exception.c | 934 ++++++++++- modules/rostests/winetests/ntdll/file.c | 750 +++++---- modules/rostests/winetests/ntdll/info.c | 625 +++++++- modules/rostests/winetests/ntdll/large_int.c | 118 +- modules/rostests/winetests/ntdll/ntdll_test.h | 4 - modules/rostests/winetests/ntdll/om.c | 1104 +++++++++++-- modules/rostests/winetests/ntdll/path.c | 9 +- modules/rostests/winetests/ntdll/pipe.c | 527 ++++++- modules/rostests/winetests/ntdll/process.c | 207 +++ modules/rostests/winetests/ntdll/reg.c | 76 +- modules/rostests/winetests/ntdll/rtl.c | 405 ++++- modules/rostests/winetests/ntdll/rtlbitmap.c | 16 +- modules/rostests/winetests/ntdll/string.c | 75 +- modules/rostests/winetests/ntdll/testlist.c | 2 + modules/rostests/winetests/ntdll/threadpool.c | 1919 +++++++++++++++++++++++ modules/rostests/winetests/ntdll/time.c | 121 ++ 18 files changed, 6783 insertions(+), 702 deletions(-)
diff --git a/modules/rostests/winetests/ntdll/CMakeLists.txt b/modules/rostests/winetests/ntdll/CMakeLists.txt index 4fe5a26ed3..f1055f85db 100644 --- a/modules/rostests/winetests/ntdll/CMakeLists.txt +++ b/modules/rostests/winetests/ntdll/CMakeLists.txt @@ -1,7 +1,7 @@
include_directories(BEFORE ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine) remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502) -add_definitions(-D__WINESRC__) +add_definitions(-D__WINESRC__ -DWINETEST_USE_DBGSTR_LONGLONG)
list(APPEND SOURCE atom.c @@ -17,6 +17,7 @@ list(APPEND SOURCE path.c pipe.c port.c + process.c reg.c rtl.c rtlbitmap.c diff --git a/modules/rostests/winetests/ntdll/directory.c b/modules/rostests/winetests/ntdll/directory.c index 89b786d384..21f22ad043 100644 --- a/modules/rostests/winetests/ntdll/directory.c +++ b/modules/rostests/winetests/ntdll/directory.c @@ -34,16 +34,20 @@ #define WIN32_NO_STATUS
#include "wine/test.h" +#include "winnls.h" #include "wine/winternl.h"
static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG ); 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 *pNtQueryInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,LONG,FILE_INFORMATION_CLASS); +static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS); static BOOLEAN (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING,LPCSTR); static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); static VOID (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); +static LONG (WINAPI *pRtlCompareUnicodeString)( const UNICODE_STRING*, const UNICODE_STRING*,BOOLEAN ); static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen, LPCSTR src, DWORD srclen ); static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirection)( BOOLEAN enable ); @@ -53,47 +57,56 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG * static struct testfile_s { BOOL attr_done; /* set if attributes were tested for this file already */ const DWORD attr; /* desired attribute */ - const char *name; /* filename to use */ + WCHAR name[20]; /* filename to use */ const char *target; /* what to point to (only for reparse pts) */ const char *description; /* for error messages */ 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" }, - { 0, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" }, - { 0, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" }, - { 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" }, - { 0, FILE_ATTRIBUTE_DIRECTORY, ".", NULL, ". directory" }, - { 0, FILE_ATTRIBUTE_DIRECTORY, "..", NULL, ".. directory" }, - { 0, 0, NULL } + { 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, + { 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, + { 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, + { 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, + { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } }; -static const int max_test_dir_size = 20; /* size of above plus some for .. etc */ +static const int test_dir_count = sizeof(testfiles) / sizeof(testfiles[0]); +static const int max_test_dir_size = sizeof(testfiles) / sizeof(testfiles[0]) + 5; /* size of above plus some for .. etc */ + +static const WCHAR dummyW[] = {'d','u','m','m','y',0}; +static const WCHAR dotW[] = {'.',0}; +static const WCHAR dotdotW[] = {'.','.',0}; +static const WCHAR backslashW[] = {'\',0};
/* Create a test directory full of attribute test files, clear counts */ -static void set_up_attribute_test(const char *testdirA) +static void set_up_attribute_test(const WCHAR *testdir) { int i; BOOL ret;
- ret = CreateDirectoryA(testdirA, NULL); - ok(ret, "couldn't create dir '%s', error %d\n", testdirA, GetLastError()); + ret = CreateDirectoryW(testdir, NULL); + ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(testdir), 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); + for (i=0; i < test_dir_count; i++) { + WCHAR buf[MAX_PATH];
- if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name, "..") == 0) + if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0) continue; - sprintf(buf, "%s\%s", testdirA, testfiles[i].name); + lstrcpyW( buf, testdir ); + lstrcatW( buf, backslashW ); + lstrcatW( buf, testfiles[i].name ); if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { - ret = CreateDirectoryA(buf, NULL); - ok(ret, "couldn't create dir '%s', error %d\n", buf, GetLastError()); + ret = CreateDirectoryW(buf, NULL); + ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(buf), GetLastError()); } else { - HANDLE h = CreateFileA(buf, + HANDLE h = CreateFileW(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, testfiles[i].attr, 0); - ok( h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf ); + ok( h != INVALID_HANDLE_VALUE, "failed to create temp file %s\n", wine_dbgstr_w(buf) ); CloseHandle(h); } } @@ -103,32 +116,34 @@ static void reset_found_files(void) { int i;
- for (i = 0; testfiles[i].name; i++) + for (i = 0; i < test_dir_count; 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) +static void tear_down_attribute_test(const WCHAR *testdir) { int i;
- for (i=0; testfiles[i].name; i++) { + for (i = 0; i < test_dir_count; i++) { int ret; - char buf[MAX_PATH]; - if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name, "..") == 0) + WCHAR buf[MAX_PATH]; + if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0) continue; - sprintf(buf, "%s\%s", testdirA, testfiles[i].name); + lstrcpyW( buf, testdir ); + lstrcatW( buf, backslashW ); + lstrcatW( buf, testfiles[i].name ); if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { - ret = RemoveDirectoryA(buf); + ret = RemoveDirectoryW(buf); ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), - "Failed to rmdir %s, error %d\n", buf, GetLastError()); + "Failed to rmdir %s, error %d\n", wine_dbgstr_w(buf), GetLastError()); } else { - ret = DeleteFileA(buf); + ret = DeleteFileW(buf); ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), - "Failed to rm %s, error %d\n", buf, GetLastError()); + "Failed to rm %s, error %d\n", wine_dbgstr_w(buf), GetLastError()); } } - RemoveDirectoryA(testdirA); + RemoveDirectoryW(testdir); }
/* Match one found file against testfiles[], increment count if found */ @@ -141,35 +156,37 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) WCHAR *nameW = dir_info->FileName; int namelen = dir_info->FileNameLength / sizeof(WCHAR);
- for (i=0; testfiles[i].name; i++) { - int len = strlen(testfiles[i].name); - if (namelen != len || memcmp(nameW, testfiles[i].nameW, len*sizeof(WCHAR))) + for (i = 0; i < test_dir_count; i++) { + int len = lstrlenW(testfiles[i].name); + if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR))) continue; if (!testfiles[i].attr_done) { - 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); + ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); testfiles[i].attr_done = TRUE; } testfiles[i].nfound++; break; } - ok(testfiles[i].name != NULL, "unexpected file found\n"); + ok(i < test_dir_count, "unexpected file found %s\n", wine_dbgstr_wn(dir_info->FileName, namelen)); }
static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char *testdirA, UNICODE_STRING *mask, BOOLEAN single_entry, BOOLEAN restart_flag) { - HANDLE dirh; + UNICODE_STRING dummy_mask; + HANDLE dirh, new_dirh; IO_STATUS_BLOCK io; UINT data_pos, data_size; UINT data_len; /* length of dir data */ BYTE data[8192]; /* directory data */ FILE_BOTH_DIRECTORY_INFORMATION *dir_info; - DWORD status; + NTSTATUS status; int numfiles; int i;
reset_found_files(); + pRtlInitUnicodeString( &dummy_mask, dummyW );
data_size = mask ? offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ) : sizeof(data);
@@ -182,12 +199,18 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char return; }
- pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size, - FileBothDirectoryInformation, single_entry, mask, restart_flag ); + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, single_entry, mask, restart_flag ); + ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status); ok (U(io).Status == STATUS_SUCCESS, "failed 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");
+ DuplicateHandle( GetCurrentProcess(), dirh, GetCurrentProcess(), &new_dirh, + 0, FALSE, DUPLICATE_SAME_ACCESS ); + pNtClose(dirh); + data_pos = 0; numfiles = 0; while ((data_pos < data_len) && (numfiles < max_test_dir_size)) { @@ -196,11 +219,12 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char tally_test_file(dir_info);
if (dir_info->NextEntryOffset == 0) { - pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, - FileBothDirectoryInformation, single_entry, mask, FALSE ); - if (U(io).Status == STATUS_NO_MORE_FILES) - break; - ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status); + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile( new_dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, single_entry, &dummy_mask, FALSE ); + ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status); + if (status == STATUS_NO_MORE_FILES) break; + ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status); data_len = io.Information; if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION)) break; @@ -213,33 +237,238 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char ok(numfiles < max_test_dir_size, "too many loops\n");
if (mask) - for (i=0; testfiles[i].name; i++) - ok(testfiles[i].nfound == (testfiles[i].nameW == mask->Buffer), + for (i = 0; i < test_dir_count; i++) + ok(testfiles[i].nfound == (testfiles[i].name == mask->Buffer), "Wrong number %d of %s files found (single_entry=%d,mask=%s)\n", testfiles[i].nfound, testfiles[i].description, single_entry, wine_dbgstr_wn(mask->Buffer, mask->Length/sizeof(WCHAR) )); else - for (i=0; testfiles[i].name; i++) + for (i = 0; i < test_dir_count; i++) ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found (single_entry=%d,restart=%d)\n", testfiles[i].nfound, testfiles[i].description, single_entry, restart_flag); - pNtClose(dirh); + pNtClose(new_dirh); }
-static void test_NtQueryDirectoryFile(void) +static void test_directory_sort( const WCHAR *testdir ) { OBJECT_ATTRIBUTES attr; UNICODE_STRING ntdirname; + IO_STATUS_BLOCK io; + UINT data_pos, data_len, count; + BYTE data[8192]; + WCHAR prev[MAX_PATH], name[MAX_PATH]; + UNICODE_STRING prev_str, name_str; + FILE_BOTH_DIRECTORY_INFORMATION *info; + NTSTATUS status; + HANDLE handle; + int res; + + if (!pRtlDosPathNameToNtPathName_U( testdir, &ntdirname, NULL, NULL )) + { + ok(0, "RtlDosPathNametoNtPathName_U failed\n"); + return; + } + InitializeObjectAttributes( &attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL ); + status = pNtOpenFile( &handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ); + ok(status == STATUS_SUCCESS, "failed to open dir %s\n", wine_dbgstr_w(testdir) ); + + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, data, sizeof(data), + FileBothDirectoryInformation, FALSE, NULL, TRUE ); + ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n", status ); + ok( U(io).Status == STATUS_SUCCESS, "failed 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" ); + data_pos = 0; + count = 0; + + while (data_pos < data_len) + { + info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos); + + memcpy( name, info->FileName, info->FileNameLength ); + name[info->FileNameLength / sizeof(WCHAR)] = 0; + switch (count) + { + case 0: /* first entry must be '.' */ + ok( !lstrcmpW( name, dotW ), "wrong name %s\n", wine_dbgstr_w( name )); + break; + case 1: /* second entry must be '..' */ + ok( !lstrcmpW( name, dotdotW ), "wrong name %s\n", wine_dbgstr_w( name )); + break; + case 2: /* nothing to compare against */ + break; + default: + pRtlInitUnicodeString( &prev_str, prev ); + pRtlInitUnicodeString( &name_str, name ); + res = pRtlCompareUnicodeString( &prev_str, &name_str, TRUE ); + ok( res < 0, "wrong result %d %s %s\n", res, wine_dbgstr_w( prev ), wine_dbgstr_w( name )); + break; + } + count++; + lstrcpyW( prev, name ); + + if (info->NextEntryOffset == 0) + { + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, sizeof(data), + FileBothDirectoryInformation, FALSE, NULL, FALSE ); + ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status); + if (status == STATUS_NO_MORE_FILES) break; + ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n", status ); + data_len = io.Information; + data_pos = 0; + } + else data_pos += info->NextEntryOffset; + } + + pNtClose( handle ); + pRtlFreeUnicodeString( &ntdirname ); +} + +static void test_NtQueryDirectoryFile_classes( HANDLE handle, UNICODE_STRING *mask ) +{ + IO_STATUS_BLOCK io; + UINT data_size; + ULONG data[256]; + NTSTATUS status; + int class; + + for (class = 0; class < FileMaximumInformation; class++) + { + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + data_size = 0; + memset( data, 0x55, sizeof(data) ); + + status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size, + class, FALSE, mask, TRUE ); + ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class, U(io).Status ); + ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class, U(io).Information ); + ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] ); + + switch (class) + { + case FileIdGlobalTxDirectoryInformation: + case FileIdExtdDirectoryInformation: + case FileIdExtdBothDirectoryInformation: + if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED) continue; + /* fall through */ + case FileDirectoryInformation: + case FileFullDirectoryInformation: + case FileBothDirectoryInformation: + case FileNamesInformation: + case FileIdBothDirectoryInformation: + case FileIdFullDirectoryInformation: + case FileObjectIdInformation: + case FileQuotaInformation: + case FileReparsePointInformation: + ok( status == STATUS_INFO_LENGTH_MISMATCH, "%u: wrong status %x\n", class, status ); + break; + default: + ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED, + "%u: wrong status %x\n", class, status ); + continue; + } + + for (data_size = 1; data_size < sizeof(data); data_size++) + { + status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size, + class, FALSE, mask, TRUE ); + if (status == STATUS_BUFFER_OVERFLOW) + { + ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, U(io).Status ); + ok( U(io).Information == data_size, "%u: wrong info %lx\n", class, U(io).Information ); + ok(data[0] == 0, "%u: wrong offset %x\n", class, data[0] ); + } + else + { + ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class, U(io).Status ); + ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class, U(io).Information ); + ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] ); + } + if (status != STATUS_INFO_LENGTH_MISMATCH) break; + } + + switch (class) + { + case FileDirectoryInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileFullDirectoryInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_FULL_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileBothDirectoryInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileNamesInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileIdBothDirectoryInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_ID_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileIdFullDirectoryInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_ID_FULL_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileIdGlobalTxDirectoryInformation: + ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); + ok( data_size == ((offsetof( FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileName[1] ) + 7) & ~7), + "%u: wrong size %u\n", class, data_size ); + break; + case FileObjectIdInformation: + ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status ); + ok( data_size == sizeof(FILE_OBJECTID_INFORMATION), "%u: wrong size %u\n", class, data_size ); + break; + case FileQuotaInformation: + ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status ); + ok( data_size == sizeof(FILE_QUOTA_INFORMATION), "%u: wrong size %u\n", class, data_size ); + break; + case FileReparsePointInformation: + ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status ); + ok( data_size == sizeof(FILE_REPARSE_POINT_INFORMATION), "%u: wrong size %u\n", class, data_size ); + break; + } + } +} + +static void test_NtQueryDirectoryFile(void) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING ntdirname, mask; char testdirA[MAX_PATH]; WCHAR testdirW[MAX_PATH]; int i; + IO_STATUS_BLOCK io; + WCHAR short_name[12]; + UINT data_size; + BYTE data[8192]; + FILE_BOTH_DIRECTORY_INFORMATION *next, *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data; + FILE_POSITION_INFORMATION pos_info; + FILE_NAMES_INFORMATION *names; + const WCHAR *filename = fbdi->FileName; + NTSTATUS status; + HANDLE dirh;
/* 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); + tear_down_attribute_test(testdirW); + set_up_attribute_test(testdirW); + if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL)) { ok(0, "RtlDosPathNametoNtPathName_U failed\n"); @@ -252,21 +481,250 @@ static void test_NtQueryDirectoryFile(void) test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, TRUE); test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, FALSE);
- for (i = 0; testfiles[i].name; i++) + for (i = 0; i < test_dir_count; i++) { - UNICODE_STRING mask; - - if (testfiles[i].nameW[0] == '.') continue; /* . and .. as masks are broken on Windows */ - mask.Buffer = testfiles[i].nameW; - mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].nameW) * sizeof(WCHAR); + if (testfiles[i].name[0] == '.') continue; /* . and .. as masks are broken on Windows */ + mask.Buffer = testfiles[i].name; + mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].name) * sizeof(WCHAR); test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE); test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, FALSE); test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, TRUE); test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE); }
+ /* short path passed as mask */ + status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); + ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA); + if (status != STATUS_SUCCESS) { + skip("can't test if we can't open the directory\n"); + return; + } + status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); + ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); + ok( pos_info.CurrentByteOffset.QuadPart == 0, "wrong pos %s\n", + wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart)); + + pos_info.CurrentByteOffset.QuadPart = 0xbeef; + status = pNtSetInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); + ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); + + status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); + ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); + ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n", + wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart)); + + mask.Buffer = testfiles[0].name; + mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].name) * sizeof(WCHAR); + data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]); + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, &mask, FALSE); + ok(status == STATUS_SUCCESS, "failed to query directory; status %x\n", status); + ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status); + ok(fbdi->ShortName[0], "ShortName is empty\n"); + + status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); + ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); + ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n", + wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) ); + + mask.Length = mask.MaximumLength = fbdi->ShortNameLength; + memcpy(short_name, fbdi->ShortName, mask.Length); + mask.Buffer = short_name; + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, &mask, TRUE); + ok(status == STATUS_SUCCESS, "failed to query directory status %x\n", status); + ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n", U(io).Status); + ok(U(io).Information == offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[lstrlenW(testfiles[0].name)]), + "wrong info %lx\n", U(io).Information); + ok(fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) && + !memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength), + "incorrect long file name: %s\n", wine_dbgstr_wn(fbdi->FileName, + fbdi->FileNameLength/sizeof(WCHAR))); + + status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); + ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); + ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n", + wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) ); + + /* tests with short buffer */ + memset( data, 0x55, data_size ); + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ); + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, &mask, TRUE); + ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status ); + ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(io).Status ); + ok( U(io).Information == data_size || broken( U(io).Information == 0), + "wrong info %lx\n", U(io).Information ); + ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset ); + ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name) * sizeof(WCHAR), + "wrong length %x\n", fbdi->FileNameLength ); + ok( filename[0] == testfiles[0].name[0], "incorrect long file name: %s\n", + wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); + ok( filename[1] == 0x5555, "incorrect long file name: %s\n", + wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); + + test_NtQueryDirectoryFile_classes( dirh, &mask ); + + /* mask may or may not be ignored when restarting the search */ + pRtlInitUnicodeString( &mask, dummyW ); + U(io).Status = 0xdeadbeef; + data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ); + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, &mask, TRUE); + ok( status == STATUS_SUCCESS || status == STATUS_NO_MORE_FILES, "wrong status %x\n", status ); + ok( U(io).Status == status, "wrong status %x / %x\n", U(io).Status, status ); + if (!status) + ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) && + !memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength), + "incorrect long file name: %s\n", + wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); + + pNtClose(dirh); + + status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); + ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA); + + memset( data, 0x55, data_size ); + data_size = sizeof(data); + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, FALSE, NULL, TRUE); + ok(status == STATUS_SUCCESS, "wrong status %x\n", status); + ok(U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status); + ok(U(io).Information > 0 && U(io).Information < data_size, "wrong info %lx\n", U(io).Information); + ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "wrong offset %x\n", fbdi->NextEntryOffset ); + ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength ); + ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); + next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset); + ok( next->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ) + 7) & ~7), + "wrong offset %x\n", next->NextEntryOffset ); + ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength ); + filename = next->FileName; + ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR))); + + data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ), + memset( data, 0x55, data_size ); + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, FALSE, NULL, TRUE ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); + ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ), + "wrong info %lx\n", U(io).Information ); + ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset ); + ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength ); + ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); + next = (FILE_BOTH_DIRECTORY_INFORMATION *)&fbdi->FileName[1]; + ok( next->NextEntryOffset == 0x55555555, "wrong offset %x\n", next->NextEntryOffset ); + + data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ), + memset( data, 0x55, data_size ); + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, FALSE, NULL, TRUE ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); + ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ), + "wrong info %lx\n", U(io).Information ); + ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset ); + + data_size = ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7) + + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ); + memset( data, 0x55, data_size ); + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, FALSE, NULL, TRUE ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); + ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size ); + ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), + "wrong offset %x\n", fbdi->NextEntryOffset ); + ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength ); + ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); + next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset); + ok( next->NextEntryOffset == 0, "wrong offset %x\n", next->NextEntryOffset ); + ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength ); + filename = next->FileName; + ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR))); + + data_size = ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7) + + offsetof( FILE_NAMES_INFORMATION, FileName[2] ); + memset( data, 0x55, data_size ); + U(io).Status = 0xdeadbeef; + U(io).Information = 0xdeadbeef; + status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, + FileNamesInformation, FALSE, NULL, TRUE ); + ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); + ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); + ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size ); + names = (FILE_NAMES_INFORMATION *)data; + ok( names->NextEntryOffset == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7), + "wrong offset %x\n", names->NextEntryOffset ); + ok( names->FileNameLength == sizeof(WCHAR), "wrong length %x\n", names->FileNameLength ); + ok( names->FileName[0] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR))); + names = (FILE_NAMES_INFORMATION *)(data + names->NextEntryOffset); + ok( names->NextEntryOffset == 0, "wrong offset %x\n", names->NextEntryOffset ); + ok( names->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", names->FileNameLength ); + filename = names->FileName; + ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n", + wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR))); + + pNtClose(dirh); + + /* create new handle to change mask */ + status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); + ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA); + + pRtlInitUnicodeString( &mask, dummyW ); + U(io).Status = 0xdeadbeef; + data_size = sizeof(data); + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, &mask, TRUE); + ok(status == STATUS_NO_SUCH_FILE, "wrong status %x\n", status); + ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status); + + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, NULL, FALSE); + ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status); + ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n", U(io).Status); + + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, NULL, TRUE); + ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status); + ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n", U(io).Status); + + pNtClose(dirh); + + U(io).Status = 0xdeadbeef; + status = pNtQueryDirectoryFile( (HANDLE)0xbeef, 0, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, NULL, TRUE ); + ok(status == STATUS_INVALID_HANDLE, "wrong status %x\n", status); + ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status); + done: - tear_down_attribute_test(testdirA); + test_directory_sort( testdirW ); + tear_down_attribute_test( testdirW ); pRtlFreeUnicodeString(&ntdirname); }
@@ -403,6 +861,8 @@ static void test_redirection(void) ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status ); status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)1 ); ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status ); + status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)0xDEADBEEF ); + ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status );
status = pRtlWow64EnableFsRedirection( FALSE ); ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); @@ -415,6 +875,7 @@ static void test_redirection(void)
START_TEST(directory) { + WCHAR sysdir[MAX_PATH]; HMODULE hntdll = GetModuleHandleA("ntdll.dll"); if (!hntdll) { @@ -425,14 +886,19 @@ START_TEST(directory) pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); + pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); + pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile"); pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); + pRtlCompareUnicodeString = (void *)GetProcAddress(hntdll, "RtlCompareUnicodeString"); pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll,"RtlMultiByteToUnicodeN"); pRtlWow64EnableFsRedirection = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirection"); pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirectionEx");
+ GetSystemDirectoryW( sysdir, MAX_PATH ); + test_directory_sort( sysdir ); test_NtQueryDirectoryFile(); test_NtQueryDirectoryFile_case(); test_redirection(); diff --git a/modules/rostests/winetests/ntdll/exception.c b/modules/rostests/winetests/ntdll/exception.c index 4bd400bb15..8dc2d90482 100644 --- a/modules/rostests/winetests/ntdll/exception.c +++ b/modules/rostests/winetests/ntdll/exception.c @@ -39,11 +39,11 @@
static void *code_mem;
-static struct _TEB * (WINAPI *pNtCurrentTeb)(void); static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*); static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*); static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec); static PVOID (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID); +static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*); static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func); static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler); static PVOID (WINAPI *pRtlAddVectoredContinueHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func); @@ -56,10 +56,72 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static NTSTATUS (WINAPI *pNtClose)(HANDLE);
#if defined(__x86_64__) +typedef struct +{ + ULONG Count; + struct + { + ULONG BeginAddress; + ULONG EndAddress; + ULONG HandlerAddress; + ULONG JumpTarget; + } ScopeRecord[1]; +} SCOPE_TABLE; + +typedef struct +{ + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + void* /*PEXCEPTION_ROUTINE*/ LanguageHandler; + PVOID HandlerData; + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; +} DISPATCHER_CONTEXT; + +typedef struct _SETJMP_FLOAT128 +{ + unsigned __int64 DECLSPEC_ALIGN(16) Part[2]; +} SETJMP_FLOAT128; + +typedef struct _JUMP_BUFFER +{ + unsigned __int64 Frame; + unsigned __int64 Rbx; + unsigned __int64 Rsp; + unsigned __int64 Rbp; + unsigned __int64 Rsi; + unsigned __int64 Rdi; + unsigned __int64 R12; + unsigned __int64 R13; + unsigned __int64 R14; + unsigned __int64 R15; + unsigned __int64 Rip; + unsigned __int64 Spare; + SETJMP_FLOAT128 Xmm6; + SETJMP_FLOAT128 Xmm7; + SETJMP_FLOAT128 Xmm8; + SETJMP_FLOAT128 Xmm9; + SETJMP_FLOAT128 Xmm10; + SETJMP_FLOAT128 Xmm11; + SETJMP_FLOAT128 Xmm12; + SETJMP_FLOAT128 Xmm13; + SETJMP_FLOAT128 Xmm14; + SETJMP_FLOAT128 Xmm15; +} _JUMP_BUFFER; + static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64); static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*); static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR); static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*); +static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*); +static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*); +static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*); +static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*, UNWIND_HISTORY_TABLE*); +static int (CDECL *p_setjmp)(_JUMP_BUFFER*); #endif
#ifdef __i386__ @@ -221,6 +283,11 @@ static const struct exception
{ { 0xf1, 0x90, 0xc3 }, /* icebp; nop; ret */ 1, 1, FALSE, STATUS_SINGLE_STEP, 0 }, + { { 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, /* mov $0xb8b8b8b8, %eax */ + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, /* mov $0xb9b9b9b9, %ecx */ + 0xba, 0xba, 0xba, 0xba, 0xba, /* mov $0xbabababa, %edx */ + 0xcd, 0x2d, 0xc3 }, /* int $0x2d; ret */ + 17, 0, FALSE, STATUS_BREAKPOINT, 3, { 0xb8b8b8b8, 0xb9b9b9b9, 0xbabababa } }, };
static int got_exception; @@ -238,16 +305,16 @@ static void run_exception_test(void *handler, const void* context, DWORD oldaccess, oldaccess2;
exc_frame.frame.Handler = handler; - exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; + exc_frame.frame.Prev = NtCurrentTeb()->Tib.ExceptionList; exc_frame.context = context;
memcpy(code_mem, code, code_size); if(access) VirtualProtect(code_mem, code_size, access, &oldaccess);
- pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; + NtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; func(); - pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; + NtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev;
if(access) VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2); @@ -263,7 +330,7 @@ static LONG CALLBACK rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *Exce ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p instead of %p\n", rec->ExceptionAddress, (char *)code_mem + 0xb);
- if (pNtCurrentTeb()->Peb->BeingDebugged) + if (NtCurrentTeb()->Peb->BeingDebugged) ok((void *)context->Eax == pRtlRaiseException || broken( is_wow64 && context->Eax == 0xf00f00f1 ), /* broken on vista */ "debugger managed to modify Eax to %x should be %p\n", @@ -360,11 +427,11 @@ static void run_rtlraiseexception_test(DWORD exceptioncode) record.NumberParameters = 0;
frame.Handler = rtlraiseexception_handler; - frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; + frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
memcpy(code_mem, call_one_arg_code, sizeof(call_one_arg_code));
- pNtCurrentTeb()->Tib.ExceptionList = &frame; + NtCurrentTeb()->Tib.ExceptionList = &frame; if (have_vectored_api) { vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &rtlraiseexception_vectored_handler); @@ -377,7 +444,7 @@ static void run_rtlraiseexception_test(DWORD exceptioncode)
if (have_vectored_api) pRtlRemoveVectoredExceptionHandler(vectored_handler); - pNtCurrentTeb()->Tib.ExceptionList = frame.Prev; + NtCurrentTeb()->Tib.ExceptionList = frame.Prev; }
static void test_rtlraiseexception(void) @@ -445,37 +512,37 @@ static void test_unwind(void)
/* add first unwind handler */ frame1->Handler = unwind_handler; - frame1->Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = frame1; + frame1->Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = frame1;
/* add second unwind handler */ frame2->Handler = unwind_handler; - frame2->Prev = pNtCurrentTeb()->Tib.ExceptionList; - pNtCurrentTeb()->Tib.ExceptionList = frame2; + frame2->Prev = NtCurrentTeb()->Tib.ExceptionList; + NtCurrentTeb()->Tib.ExceptionList = frame2;
/* test unwind to current frame */ unwind_expected_eax = 0xDEAD0000; retval = func(pRtlUnwind, frame2, NULL, 0xDEAD0000); ok(retval == 0xDEAD0000, "RtlUnwind returned eax %08x instead of %08x\n", retval, 0xDEAD0000); - ok(pNtCurrentTeb()->Tib.ExceptionList == frame2, "Exception record points to %p instead of %p\n", - pNtCurrentTeb()->Tib.ExceptionList, frame2); + ok(NtCurrentTeb()->Tib.ExceptionList == frame2, "Exception record points to %p instead of %p\n", + NtCurrentTeb()->Tib.ExceptionList, frame2);
/* unwind to frame1 */ unwind_expected_eax = 0xDEAD0000; retval = func(pRtlUnwind, frame1, NULL, 0xDEAD0000); ok(retval == 0xDEAD0001, "RtlUnwind returned eax %08x instead of %08x\n", retval, 0xDEAD0001); - ok(pNtCurrentTeb()->Tib.ExceptionList == frame1, "Exception record points to %p instead of %p\n", - pNtCurrentTeb()->Tib.ExceptionList, frame1); + ok(NtCurrentTeb()->Tib.ExceptionList == frame1, "Exception record points to %p instead of %p\n", + NtCurrentTeb()->Tib.ExceptionList, frame1);
/* restore original handler */ - pNtCurrentTeb()->Tib.ExceptionList = frame1->Prev; + NtCurrentTeb()->Tib.ExceptionList = frame1->Prev; }
static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { const struct exception *except = *(const struct exception **)(frame + 1); - unsigned int i, entry = except - exceptions; + unsigned int i, parameter_count, entry = except - exceptions;
got_exception++; trace( "exception %u: %x flags:%x addr:%p\n", @@ -484,20 +551,23 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram 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 ); - - 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 ); - } + ok( context->Eip == (DWORD_PTR)code_mem + except->offset, + "%u: Unexpected eip %#x/%#lx\n", entry, + context->Eip, (DWORD_PTR)code_mem + except->offset ); + ok( rec->ExceptionAddress == (char*)context->Eip || + (rec->ExceptionCode == STATUS_BREAKPOINT && rec->ExceptionAddress == (char*)context->Eip + 1), + "%u: Unexpected exception address %p/%p\n", entry, + rec->ExceptionAddress, (char*)context->Eip ); + + if (except->status == STATUS_BREAKPOINT && is_wow64) + parameter_count = 1; + else if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status) + parameter_count = 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 ); - } + parameter_count = except->alt_nb_params; + + ok( rec->NumberParameters == parameter_count, + "%u: Unexpected parameter count %u/%u\n", entry, rec->NumberParameters, parameter_count );
/* Most CPUs (except Intel Core apparently) report a segment limit violation */ /* instead of page faults for accesses beyond 0xffffffff */ @@ -532,7 +602,7 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram
skip_params: /* don't handle exception if it's not the address we expected */ - if (rec->ExceptionAddress != (char*)code_mem + except->offset) return ExceptionContinueSearch; + if (context->Eip != (DWORD_PTR)code_mem + except->offset) return ExceptionContinueSearch;
context->Eip += except->length; return ExceptionContinueExecution; @@ -754,12 +824,21 @@ static DWORD int3_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD
static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */
+static DWORD WINAPI hw_reg_exception_thread( void *arg ) +{ + int expect = (ULONG_PTR)arg; + got_exception = 0; + run_exception_test( bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0 ); + ok( got_exception == expect, "expected %u exceptions, got %d\n", expect, got_exception ); + return 0; +}
static void test_exceptions(void) { CONTEXT ctx; NTSTATUS res; struct dbgreg_test dreg_test; + HANDLE h;
if (!pNtGetContextThread || !pNtSetContextThread) { @@ -813,6 +892,33 @@ static void test_exceptions(void)
/* test int3 handling */ run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code), 0); + + /* test that hardware breakpoints are not inherited by created threads */ + res = pNtSetContextThread( GetCurrentThread(), &ctx ); + ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res ); + + h = CreateThread( NULL, 0, hw_reg_exception_thread, 0, 0, NULL ); + WaitForSingleObject( h, 10000 ); + CloseHandle( h ); + + h = CreateThread( NULL, 0, hw_reg_exception_thread, (void *)4, CREATE_SUSPENDED, NULL ); + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + res = pNtGetContextThread( h, &ctx ); + ok( res == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", res ); + ok( ctx.Dr0 == 0, "dr0 %x\n", ctx.Dr0 ); + ok( ctx.Dr7 == 0, "dr7 %x\n", ctx.Dr7 ); + ctx.Dr0 = (DWORD)code_mem; + ctx.Dr7 = 3; + res = pNtSetContextThread( h, &ctx ); + ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res ); + ResumeThread( h ); + WaitForSingleObject( h, 10000 ); + CloseHandle( h ); + + ctx.Dr0 = 0; + ctx.Dr7 = 0; + res = pNtSetContextThread( GetCurrentThread(), &ctx ); + ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res ); }
static void test_debugger(void) @@ -855,7 +961,7 @@ static void test_debugger(void)
if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { - if(de.u.CreateProcessInfo.lpBaseOfImage != pNtCurrentTeb()->Peb->ImageBaseAddress) + if(de.u.CreateProcessInfo.lpBaseOfImage != NtCurrentTeb()->Peb->ImageBaseAddress) { skip("child process loaded at different address, terminating it\n"); pNtTerminateProcess(pi.hProcess, 0); @@ -940,6 +1046,24 @@ static void test_debugger(void) } } else if (stage == 7 || stage == 8) + { + ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, + "expected EXCEPTION_BREAKPOINT, got %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode); + ok((char *)ctx.Eip == (char *)code_mem_address + 0x1d, + "expected Eip = %p, got 0x%x\n", (char *)code_mem_address + 0x1d, ctx.Eip); + + if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + } + else if (stage == 9 || stage == 10) + { + ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, + "expected EXCEPTION_BREAKPOINT, got %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode); + ok((char *)ctx.Eip == (char *)code_mem_address + 2, + "expected Eip = %p, got 0x%x\n", (char *)code_mem_address + 2, ctx.Eip); + + if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + } + else if (stage == 11 || stage == 12) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08x, expected %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -947,7 +1071,7 @@ static void test_debugger(void) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %d, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
- if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else ok(FALSE, "unexpected stage %x\n", stage); @@ -1035,22 +1159,25 @@ static DWORD simd_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_R context->Eip += 3; /* skip addps */ return ExceptionContinueExecution; } - - /* stage 2 - divide by zero fault */ - if( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) - skip("system doesn't support SIMD exceptions\n"); - else { - ok( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS, - "exception code: %#x, should be %#x\n", - rec->ExceptionCode, STATUS_FLOAT_MULTIPLE_TRAPS); - ok( rec->NumberParameters == 1 || broken(is_wow64 && rec->NumberParameters == 2), - "# of params: %i, should be 1\n", - rec->NumberParameters); - if( rec->NumberParameters == 1 ) - ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be 0\n", rec->ExceptionInformation[0]); + else if ( *stage == 2 || *stage == 3 ) { + /* stage 2 - divide by zero fault */ + /* stage 3 - invalid operation fault */ + if( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) + skip("system doesn't support SIMD exceptions\n"); + else { + ok( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS, + "exception code: %#x, should be %#x\n", + rec->ExceptionCode, STATUS_FLOAT_MULTIPLE_TRAPS); + ok( rec->NumberParameters == 1 || broken(is_wow64 && rec->NumberParameters == 2), + "# of params: %i, should be 1\n", + rec->NumberParameters); + if( rec->NumberParameters == 1 ) + ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be 0\n", rec->ExceptionInformation[0]); + } + context->Eip += 3; /* skip divps */ } - - context->Eip += 3; /* skip divps */ + else + ok(FALSE, "unexpected stage %x\n", *stage);
return ExceptionContinueExecution; } @@ -1058,6 +1185,7 @@ static DWORD simd_fault_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_R static const BYTE simd_exception_test[] = { 0x83, 0xec, 0x4, /* sub $0x4, %esp */ 0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */ + 0x8b, 0x04, 0x24, /* mov (%esp),%eax * store mxcsr */ 0x66, 0x81, 0x24, 0x24, 0xff, 0xfd, /* andw $0xfdff,(%esp) * enable divide by */ 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * zero exceptions */ 0x6a, 0x01, /* push $0x1 */ @@ -1068,7 +1196,22 @@ static const BYTE simd_exception_test[] = { 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */ 0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */ 0x83, 0xc4, 0x10, /* add $0x10,%esp */ - 0x66, 0x81, 0x0c, 0x24, 0x00, 0x02, /* orw $0x200,(%esp) * disable exceptions */ + 0x89, 0x04, 0x24, /* mov %eax,(%esp) * restore to old mxcsr */ + 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */ + 0x83, 0xc4, 0x04, /* add $0x4,%esp */ + 0xc3, /* ret */ +}; + +static const BYTE simd_exception_test2[] = { + 0x83, 0xec, 0x4, /* sub $0x4, %esp */ + 0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */ + 0x8b, 0x04, 0x24, /* mov (%esp),%eax * store mxcsr */ + 0x66, 0x81, 0x24, 0x24, 0x7f, 0xff, /* andw $0xff7f,(%esp) * enable invalid */ + 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * operation exceptions */ + 0x0f, 0x57, 0xc9, /* xorps %xmm1,%xmm1 * clear dividend */ + 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */ + 0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */ + 0x89, 0x04, 0x24, /* mov %eax,(%esp) * restore to old mxcsr */ 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */ 0x83, 0xc4, 0x04, /* add $0x4,%esp */ 0xc3, /* ret */ @@ -1097,7 +1240,14 @@ static void test_simd_exceptions(void) got_exception = 0; run_exception_test(simd_fault_handler, &stage, simd_exception_test, sizeof(simd_exception_test), 0); - ok( got_exception == 1, "got exception: %i, should be 1\n", got_exception); + ok(got_exception == 1, "got exception: %i, should be 1\n", got_exception); + + /* generate a SIMD exception, test FPE_FLTINV */ + stage = 3; + got_exception = 0; + run_exception_test(simd_fault_handler, &stage, simd_exception_test2, + sizeof(simd_exception_test2), 0); + ok(got_exception == 1, "got exception: %i, should be 1\n", got_exception); }
struct fpu_exception_info @@ -1166,7 +1316,7 @@ static void test_fpu_exceptions(void) ok(info.exception_code == EXCEPTION_FLT_STACK_CHECK, "Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK\n", info.exception_code); ok(info.exception_offset == 0x19 || - broken( is_wow64 && info.exception_offset == info.eip_offset ), + broken( info.exception_offset == info.eip_offset ), "Got exception offset %#x, expected 0x19\n", info.exception_offset); ok(info.eip_offset == 0x1b, "Got EIP offset %#x, expected 0x1b\n", info.eip_offset);
@@ -1175,7 +1325,7 @@ static void test_fpu_exceptions(void) ok(info.exception_code == EXCEPTION_FLT_DIVIDE_BY_ZERO, "Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO\n", info.exception_code); ok(info.exception_offset == 0x17 || - broken( is_wow64 && info.exception_offset == info.eip_offset ), + broken( info.exception_offset == info.eip_offset ), "Got exception offset %#x, expected 0x17\n", info.exception_offset); ok(info.eip_offset == 0x19, "Got EIP offset %#x, expected 0x19\n", info.eip_offset); } @@ -1323,8 +1473,138 @@ static void test_dpe_exceptions(void) ok(stat == STATUS_ACCESS_DENIED, "enabling DEP while permanent: status %08x\n", stat); }
+static void test_thread_context(void) +{ + CONTEXT context; + NTSTATUS status; + struct expected + { + DWORD Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp, Esp, Eip, + SegCs, SegDs, SegEs, SegFs, SegGs, SegSs, EFlags, prev_frame; + } expect; + NTSTATUS (*func_ptr)( struct expected *res, void *func, void *arg1, void *arg2 ) = (void *)code_mem; + + static const BYTE call_func[] = + { + 0x55, /* pushl %ebp */ + 0x89, 0xe5, /* mov %esp,%ebp */ + 0x50, /* pushl %eax ; add a bit of offset to the stack */ + 0x50, /* pushl %eax */ + 0x50, /* pushl %eax */ + 0x50, /* pushl %eax */ + 0x8b, 0x45, 0x08, /* mov 0x8(%ebp),%eax */ + 0x8f, 0x00, /* popl (%eax) */ + 0x89, 0x58, 0x04, /* mov %ebx,0x4(%eax) */ + 0x89, 0x48, 0x08, /* mov %ecx,0x8(%eax) */ + 0x89, 0x50, 0x0c, /* mov %edx,0xc(%eax) */ + 0x89, 0x70, 0x10, /* mov %esi,0x10(%eax) */ + 0x89, 0x78, 0x14, /* mov %edi,0x14(%eax) */ + 0x89, 0x68, 0x18, /* mov %ebp,0x18(%eax) */ + 0x89, 0x60, 0x1c, /* mov %esp,0x1c(%eax) */ + 0xff, 0x75, 0x04, /* pushl 0x4(%ebp) */ + 0x8f, 0x40, 0x20, /* popl 0x20(%eax) */ + 0x8c, 0x48, 0x24, /* mov %cs,0x24(%eax) */ + 0x8c, 0x58, 0x28, /* mov %ds,0x28(%eax) */ + 0x8c, 0x40, 0x2c, /* mov %es,0x2c(%eax) */ + 0x8c, 0x60, 0x30, /* mov %fs,0x30(%eax) */ + 0x8c, 0x68, 0x34, /* mov %gs,0x34(%eax) */ + 0x8c, 0x50, 0x38, /* mov %ss,0x38(%eax) */ + 0x9c, /* pushf */ + 0x8f, 0x40, 0x3c, /* popl 0x3c(%eax) */ + 0xff, 0x75, 0x00, /* pushl 0x0(%ebp) ; previous stack frame */ + 0x8f, 0x40, 0x40, /* popl 0x40(%eax) */ + 0x8b, 0x00, /* mov (%eax),%eax */ + 0xff, 0x75, 0x14, /* pushl 0x14(%ebp) */ + 0xff, 0x75, 0x10, /* pushl 0x10(%ebp) */ + 0xff, 0x55, 0x0c, /* call *0xc(%ebp) */ + 0xc9, /* leave */ + 0xc3, /* ret */ + }; + + memcpy( func_ptr, call_func, sizeof(call_func) ); + +#define COMPARE(reg) \ + ok( context.reg == expect.reg, "wrong " #reg " %08x/%08x\n", context.reg, expect.reg ) + + memset( &context, 0xcc, sizeof(context) ); + memset( &expect, 0xcc, sizeof(expect) ); + func_ptr( &expect, pRtlCaptureContext, &context, 0 ); + trace( "expect: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x " + "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x prev=%08x\n", + expect.Eax, expect.Ebx, expect.Ecx, expect.Edx, expect.Esi, expect.Edi, + expect.Ebp, expect.Esp, expect.Eip, expect.SegCs, expect.SegDs, expect.SegEs, + expect.SegFs, expect.SegGs, expect.SegSs, expect.EFlags, expect.prev_frame ); + trace( "actual: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x " + "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n", + context.Eax, context.Ebx, context.Ecx, context.Edx, context.Esi, context.Edi, + context.Ebp, context.Esp, context.Eip, context.SegCs, context.SegDs, context.SegEs, + context.SegFs, context.SegGs, context.SegSs, context.EFlags ); + + ok( context.ContextFlags == (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) || + broken( context.ContextFlags == 0xcccccccc ), /* <= vista */ + "wrong flags %08x\n", context.ContextFlags ); + COMPARE( Eax ); + COMPARE( Ebx ); + COMPARE( Ecx ); + COMPARE( Edx ); + COMPARE( Esi ); + COMPARE( Edi ); + COMPARE( Eip ); + COMPARE( SegCs ); + COMPARE( SegDs ); + COMPARE( SegEs ); + COMPARE( SegFs ); + COMPARE( SegGs ); + COMPARE( SegSs ); + COMPARE( EFlags ); + /* Ebp is from the previous stackframe */ + ok( context.Ebp == expect.prev_frame, "wrong Ebp %08x/%08x\n", context.Ebp, expect.prev_frame ); + /* Esp is the value on entry to the previous stackframe */ + ok( context.Esp == expect.Ebp + 8, "wrong Esp %08x/%08x\n", context.Esp, expect.Ebp + 8 ); + + memset( &context, 0xcc, sizeof(context) ); + memset( &expect, 0xcc, sizeof(expect) ); + context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; + status = func_ptr( &expect, pNtGetContextThread, (void *)GetCurrentThread(), &context ); + ok( status == STATUS_SUCCESS, "NtGetContextThread failed %08x\n", status ); + trace( "expect: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x " + "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x prev=%08x\n", + expect.Eax, expect.Ebx, expect.Ecx, expect.Edx, expect.Esi, expect.Edi, + expect.Ebp, expect.Esp, expect.Eip, expect.SegCs, expect.SegDs, expect.SegEs, + expect.SegFs, expect.SegGs, expect.SegSs, expect.EFlags, expect.prev_frame ); + trace( "actual: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x esp=%08x " + "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x\n", + context.Eax, context.Ebx, context.Ecx, context.Edx, context.Esi, context.Edi, + context.Ebp, context.Esp, context.Eip, context.SegCs, context.SegDs, context.SegEs, + context.SegFs, context.SegGs, context.SegSs, context.EFlags ); + /* Eax, Ecx, Edx, EFlags are not preserved */ + COMPARE( Ebx ); + COMPARE( Esi ); + COMPARE( Edi ); + COMPARE( Ebp ); + /* Esp is the stack upon entry to NtGetContextThread */ + ok( context.Esp == expect.Esp - 12 || context.Esp == expect.Esp - 16, + "wrong Esp %08x/%08x\n", context.Esp, expect.Esp ); + /* Eip is somewhere close to the NtGetContextThread implementation */ + ok( (char *)context.Eip >= (char *)pNtGetContextThread - 0x10000 && + (char *)context.Eip <= (char *)pNtGetContextThread + 0x10000, + "wrong Eip %08x/%08x\n", context.Eip, (DWORD)pNtGetContextThread ); + ok( *(WORD *)context.Eip == 0xc483 || *(WORD *)context.Eip == 0x08c2 || *(WORD *)context.Eip == 0x8dc3, + "expected 0xc483 or 0x08c2 or 0x8dc3, got %04x\n", *(WORD *)context.Eip ); + /* segment registers clear the high word */ + ok( context.SegCs == LOWORD(expect.SegCs), "wrong SegCs %08x/%08x\n", context.SegCs, expect.SegCs ); + ok( context.SegDs == LOWORD(expect.SegDs), "wrong SegDs %08x/%08x\n", context.SegDs, expect.SegDs ); + ok( context.SegEs == LOWORD(expect.SegEs), "wrong SegEs %08x/%08x\n", context.SegEs, expect.SegEs ); + ok( context.SegFs == LOWORD(expect.SegFs), "wrong SegFs %08x/%08x\n", context.SegFs, expect.SegFs ); + ok( context.SegGs == LOWORD(expect.SegGs), "wrong SegGs %08x/%08x\n", context.SegGs, expect.SegGs ); + ok( context.SegSs == LOWORD(expect.SegSs), "wrong SegSs %08x/%08x\n", context.SegSs, expect.SegGs ); +#undef COMPARE +} + #elif defined(__x86_64__)
+#define is_wow64 0 + #define UNW_FLAG_NHANDLER 0 #define UNW_FLAG_EHANDLER 1 #define UNW_FLAG_UHANDLER 2 @@ -1598,6 +1878,131 @@ static void test_virtual_unwind(void) call_virtual_unwind( i, &tests[i] ); }
+static int consolidate_dummy_called; +static PVOID CALLBACK test_consolidate_dummy(EXCEPTION_RECORD *rec) +{ + CONTEXT *ctx = (CONTEXT *)rec->ExceptionInformation[1]; + consolidate_dummy_called = 1; + ok(ctx->Rip == 0xdeadbeef, "test_consolidate_dummy failed for Rip, expected: 0xdeadbeef, got: %lx\n", ctx->Rip); + return (PVOID)rec->ExceptionInformation[2]; +} + +static void test_restore_context(void) +{ + SETJMP_FLOAT128 *fltsave; + EXCEPTION_RECORD rec; + _JUMP_BUFFER buf; + CONTEXT ctx; + int i, pass; + + if (!pRtlUnwindEx || !pRtlRestoreContext || !pRtlCaptureContext || !p_setjmp) + { + skip("RtlUnwindEx/RtlCaptureContext/RtlRestoreContext/_setjmp not found\n"); + return; + } + + /* RtlRestoreContext(NULL, NULL); crashes on Windows */ + + /* test simple case of capture and restore context */ + pass = 0; + InterlockedIncrement(&pass); /* interlocked to prevent compiler from moving after capture */ + pRtlCaptureContext(&ctx); + if (InterlockedIncrement(&pass) == 2) /* interlocked to prevent compiler from moving before capture */ + { + pRtlRestoreContext(&ctx, NULL); + ok(0, "shouldn't be reached\n"); + } + else + ok(pass < 4, "unexpected pass %d\n", pass); + + /* test with jmp using RltRestoreContext */ + pass = 0; + InterlockedIncrement(&pass); + RtlCaptureContext(&ctx); + InterlockedIncrement(&pass); /* only called once */ + p_setjmp(&buf); + InterlockedIncrement(&pass); + if (pass == 3) + { + rec.ExceptionCode = STATUS_LONGJUMP; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = (DWORD64)&buf; + + /* uses buf.Rip instead of ctx.Rip */ + pRtlRestoreContext(&ctx, &rec); + ok(0, "shouldn't be reached\n"); + } + else if (pass == 4) + { + ok(buf.Rbx == ctx.Rbx, "longjmp failed for Rbx, expected: %lx, got: %lx\n", buf.Rbx, ctx.Rbx); + ok(buf.Rsp == ctx.Rsp, "longjmp failed for Rsp, expected: %lx, got: %lx\n", buf.Rsp, ctx.Rsp); + ok(buf.Rbp == ctx.Rbp, "longjmp failed for Rbp, expected: %lx, got: %lx\n", buf.Rbp, ctx.Rbp); + ok(buf.Rsi == ctx.Rsi, "longjmp failed for Rsi, expected: %lx, got: %lx\n", buf.Rsi, ctx.Rsi); + ok(buf.Rdi == ctx.Rdi, "longjmp failed for Rdi, expected: %lx, got: %lx\n", buf.Rdi, ctx.Rdi); + ok(buf.R12 == ctx.R12, "longjmp failed for R12, expected: %lx, got: %lx\n", buf.R12, ctx.R12); + ok(buf.R13 == ctx.R13, "longjmp failed for R13, expected: %lx, got: %lx\n", buf.R13, ctx.R13); + ok(buf.R14 == ctx.R14, "longjmp failed for R14, expected: %lx, got: %lx\n", buf.R14, ctx.R14); + ok(buf.R15 == ctx.R15, "longjmp failed for R15, expected: %lx, got: %lx\n", buf.R15, ctx.R15); + + fltsave = &buf.Xmm6; + for (i = 0; i < 10; i++) + { + ok(fltsave[i].Part[0] == ctx.u.FltSave.XmmRegisters[i + 6].Low, + "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6, + fltsave[i].Part[0], ctx.u.FltSave.XmmRegisters[i + 6].Low); + + ok(fltsave[i].Part[1] == ctx.u.FltSave.XmmRegisters[i + 6].High, + "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6, + fltsave[i].Part[1], ctx.u.FltSave.XmmRegisters[i + 6].High); + } + } + else + ok(0, "unexpected pass %d\n", pass); + + /* test with jmp through RtlUnwindEx */ + pass = 0; + InterlockedIncrement(&pass); + pRtlCaptureContext(&ctx); + InterlockedIncrement(&pass); /* only called once */ + p_setjmp(&buf); + InterlockedIncrement(&pass); + if (pass == 3) + { + rec.ExceptionCode = STATUS_LONGJUMP; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = (DWORD64)&buf; + + /* uses buf.Rip instead of bogus 0xdeadbeef */ + pRtlUnwindEx((void*)buf.Rsp, (void*)0xdeadbeef, &rec, NULL, &ctx, NULL); + ok(0, "shouldn't be reached\n"); + } + else + ok(pass == 4, "unexpected pass %d\n", pass); + + + /* test with consolidate */ + pass = 0; + InterlockedIncrement(&pass); + RtlCaptureContext(&ctx); + InterlockedIncrement(&pass); + if (pass == 2) + { + rec.ExceptionCode = STATUS_UNWIND_CONSOLIDATE; + rec.NumberParameters = 3; + rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy; + rec.ExceptionInformation[1] = (DWORD64)&ctx; + rec.ExceptionInformation[2] = ctx.Rip; + ctx.Rip = 0xdeadbeef; + + pRtlRestoreContext(&ctx, &rec); + ok(0, "shouldn't be reached\n"); + } + else if (pass == 3) + ok(consolidate_dummy_called, "test_consolidate_dummy not called\n"); + else + ok(0, "unexpected pass %d\n", pass); +} + static RUNTIME_FUNCTION* CALLBACK dynamic_unwind_callback( DWORD64 pc, PVOID context ) { static const int code_offset = 1024; @@ -1714,9 +2119,155 @@ static void test_dynamic_unwind(void)
}
+static int termination_handler_called; +static void WINAPI termination_handler(ULONG flags, ULONG64 frame) +{ + termination_handler_called++; + + ok(flags == 1 || broken(flags == 0x401), "flags = %x\n", flags); + ok(frame == 0x1234, "frame = %p\n", (void*)frame); +} + +static void test___C_specific_handler(void) +{ + DISPATCHER_CONTEXT dispatch; + EXCEPTION_RECORD rec; + CONTEXT context; + ULONG64 frame; + EXCEPTION_DISPOSITION ret; + SCOPE_TABLE scope_table; + + if (!p__C_specific_handler) + { + win_skip("__C_specific_handler not available\n"); + return; + } + + memset(&rec, 0, sizeof(rec)); + rec.ExceptionFlags = 2; /* EH_UNWINDING */ + frame = 0x1234; + memset(&dispatch, 0, sizeof(dispatch)); + dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL); + dispatch.ControlPc = dispatch.ImageBase + 0x200; + dispatch.HandlerData = &scope_table; + dispatch.ContextRecord = &context; + scope_table.Count = 1; + scope_table.ScopeRecord[0].BeginAddress = 0x200; + scope_table.ScopeRecord[0].EndAddress = 0x400; + scope_table.ScopeRecord[0].HandlerAddress = (ULONG_PTR)termination_handler-dispatch.ImageBase; + scope_table.ScopeRecord[0].JumpTarget = 0; + memset(&context, 0, sizeof(context)); + + termination_handler_called = 0; + ret = p__C_specific_handler(&rec, frame, &context, &dispatch); + ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret); + ok(termination_handler_called == 1, "termination_handler_called = %d\n", + termination_handler_called); + ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex); + + ret = p__C_specific_handler(&rec, frame, &context, &dispatch); + ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n", ret); + ok(termination_handler_called == 1, "termination_handler_called = %d\n", + termination_handler_called); + ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n", dispatch.ScopeIndex); +} + #endif /* __x86_64__ */
#if defined(__i386__) || defined(__x86_64__) + +static DWORD WINAPI register_check_thread(void *arg) +{ + NTSTATUS status; + CONTEXT ctx; + + memset(&ctx, 0, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + + status = pNtGetContextThread(GetCurrentThread(), &ctx); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status); + ok(!ctx.Dr0, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr0); + ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1); + ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2); + ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3); + ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6); + ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7); + + return 0; +} + +static void test_debug_registers(void) +{ + static const struct + { + ULONG_PTR dr0, dr1, dr2, dr3, dr6, dr7; + } + tests[] = + { + { 0x42424240, 0, 0x126bb070, 0x0badbad0, 0, 0xffff0115 }, + { 0x42424242, 0, 0x100f0fe7, 0x0abebabe, 0, 0x115 }, + }; + NTSTATUS status; + CONTEXT ctx; + HANDLE thread; + int i; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + { + memset(&ctx, 0, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + ctx.Dr0 = tests[i].dr0; + ctx.Dr1 = tests[i].dr1; + ctx.Dr2 = tests[i].dr2; + ctx.Dr3 = tests[i].dr3; + ctx.Dr6 = tests[i].dr6; + ctx.Dr7 = tests[i].dr7; + + status = pNtSetContextThread(GetCurrentThread(), &ctx); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n", status); + + memset(&ctx, 0, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + + status = pNtGetContextThread(GetCurrentThread(), &ctx); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n", status); + ok(ctx.Dr0 == tests[i].dr0, "test %d: expected %lx, got %lx\n", i, tests[i].dr0, (DWORD_PTR)ctx.Dr0); + ok(ctx.Dr1 == tests[i].dr1, "test %d: expected %lx, got %lx\n", i, tests[i].dr1, (DWORD_PTR)ctx.Dr1); + ok(ctx.Dr2 == tests[i].dr2, "test %d: expected %lx, got %lx\n", i, tests[i].dr2, (DWORD_PTR)ctx.Dr2); + ok(ctx.Dr3 == tests[i].dr3, "test %d: expected %lx, got %lx\n", i, tests[i].dr3, (DWORD_PTR)ctx.Dr3); + ok((ctx.Dr6 & 0xf00f) == tests[i].dr6, "test %d: expected %lx, got %lx\n", i, tests[i].dr6, (DWORD_PTR)ctx.Dr6); + ok((ctx.Dr7 & ~0xdc00) == tests[i].dr7, "test %d: expected %lx, got %lx\n", i, tests[i].dr7, (DWORD_PTR)ctx.Dr7); + } + + memset(&ctx, 0, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + ctx.Dr0 = 0xffffffff; + ctx.Dr1 = 0xffffffff; + ctx.Dr2 = 0xffffffff; + ctx.Dr3 = 0xffffffff; + ctx.Dr6 = 0xffffffff; + ctx.Dr7 = 0x00000400; + status = pNtSetContextThread(GetCurrentThread(), &ctx); + ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", status); + + thread = CreateThread(NULL, 0, register_check_thread, NULL, CREATE_SUSPENDED, NULL); + ok(thread != INVALID_HANDLE_VALUE, "CreateThread failed with %d\n", GetLastError()); + + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + status = pNtGetContextThread(thread, &ctx); + ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", status); + ok(!ctx.Dr0, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr0); + ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1); + ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2); + ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3); + ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6); + ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7); + + ResumeThread(thread); + WaitForSingleObject(thread, 10000); + CloseHandle(thread); +} + static DWORD outputdebugstring_exceptions;
static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) @@ -1750,6 +2301,7 @@ static void test_outputdebugstring(DWORD numexc)
outputdebugstring_exceptions = 0; OutputDebugStringA("Hello World"); + ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n", outputdebugstring_exceptions, numexc);
@@ -1805,6 +2357,236 @@ static void test_ripevent(DWORD numexc) pRtlRemoveVectoredExceptionHandler(vectored_handler); }
+static DWORD debug_service_exceptions; + +static LONG CALLBACK debug_service_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord; + trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress); + + ok(rec->ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode is %08x instead of %08x\n", + rec->ExceptionCode, EXCEPTION_BREAKPOINT); + +#ifdef __i386__ + ok(ExceptionInfo->ContextRecord->Eip == (DWORD)code_mem + 0x1c, + "expected Eip = %x, got %x\n", (DWORD)code_mem + 0x1c, ExceptionInfo->ContextRecord->Eip); + ok(rec->NumberParameters == (is_wow64 ? 1 : 3), + "ExceptionParameters is %d instead of %d\n", rec->NumberParameters, is_wow64 ? 1 : 3); + ok(rec->ExceptionInformation[0] == ExceptionInfo->ContextRecord->Eax, + "expected ExceptionInformation[0] = %x, got %lx\n", + ExceptionInfo->ContextRecord->Eax, rec->ExceptionInformation[0]); + if (!is_wow64) + { + ok(rec->ExceptionInformation[1] == 0x11111111, + "got ExceptionInformation[1] = %lx\n", rec->ExceptionInformation[1]); + ok(rec->ExceptionInformation[2] == 0x22222222, + "got ExceptionInformation[2] = %lx\n", rec->ExceptionInformation[2]); + } +#else + ok(ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)code_mem + 0x2f, + "expected Rip = %lx, got %lx\n", (DWORD_PTR)code_mem + 0x2f, ExceptionInfo->ContextRecord->Rip); + ok(rec->NumberParameters == 1, + "ExceptionParameters is %d instead of 1\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == ExceptionInfo->ContextRecord->Rax, + "expected ExceptionInformation[0] = %lx, got %lx\n", + ExceptionInfo->ContextRecord->Rax, rec->ExceptionInformation[0]); +#endif + + debug_service_exceptions++; + return (rec->ExceptionCode == EXCEPTION_BREAKPOINT) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} + +#ifdef __i386__ + +static const BYTE call_debug_service_code[] = { + 0x53, /* pushl %ebx */ + 0x57, /* pushl %edi */ + 0x8b, 0x44, 0x24, 0x0c, /* movl 12(%esp),%eax */ + 0xb9, 0x11, 0x11, 0x11, 0x11, /* movl $0x11111111,%ecx */ + 0xba, 0x22, 0x22, 0x22, 0x22, /* movl $0x22222222,%edx */ + 0xbb, 0x33, 0x33, 0x33, 0x33, /* movl $0x33333333,%ebx */ + 0xbf, 0x44, 0x44, 0x44, 0x44, /* movl $0x44444444,%edi */ + 0xcd, 0x2d, /* int $0x2d */ + 0xeb, /* jmp $+17 */ + 0x0f, 0x1f, 0x00, /* nop */ + 0x31, 0xc0, /* xorl %eax,%eax */ + 0xeb, 0x0c, /* jmp $+14 */ + 0x90, 0x90, 0x90, 0x90, /* nop */ + 0x90, 0x90, 0x90, 0x90, + 0x90, + 0x31, 0xc0, /* xorl %eax,%eax */ + 0x40, /* incl %eax */ + 0x5f, /* popl %edi */ + 0x5b, /* popl %ebx */ + 0xc3, /* ret */ +}; + +#else + +static const BYTE call_debug_service_code[] = { + 0x53, /* push %rbx */ + 0x57, /* push %rdi */ + 0x48, 0x89, 0xc8, /* movl %rcx,%rax */ + 0x48, 0xb9, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /* movabs $0x1111111111111111,%rcx */ + 0x48, 0xba, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* movabs $0x2222222222222222,%rdx */ + 0x48, 0xbb, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, /* movabs $0x3333333333333333,%rbx */ + 0x48, 0xbf, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, /* movabs $0x4444444444444444,%rdi */ + 0xcd, 0x2d, /* int $0x2d */ + 0xeb, /* jmp $+17 */ + 0x0f, 0x1f, 0x00, /* nop */ + 0x48, 0x31, 0xc0, /* xor %rax,%rax */ + 0xeb, 0x0e, /* jmp $+16 */ + 0x90, 0x90, 0x90, 0x90, /* nop */ + 0x90, 0x90, 0x90, 0x90, + 0x48, 0x31, 0xc0, /* xor %rax,%rax */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x5f, /* pop %rdi */ + 0x5b, /* pop %rbx */ + 0xc3, /* ret */ +}; + +#endif + +static void test_debug_service(DWORD numexc) +{ + DWORD (CDECL *func)(DWORD_PTR) = code_mem; + DWORD expected_exc, expected_ret; + void *vectored_handler; + DWORD ret; + + /* code will return 0 if execution resumes immediately after "int $0x2d", otherwise 1 */ + memcpy(code_mem, call_debug_service_code, sizeof(call_debug_service_code)); + + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &debug_service_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + + expected_exc = numexc; + expected_ret = (numexc != 0); + + /* BREAKPOINT_BREAK */ + debug_service_exceptions = 0; + ret = func(0); + ok(debug_service_exceptions == expected_exc, + "BREAKPOINT_BREAK generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret, + "BREAKPOINT_BREAK returned %u, expected %u\n", ret, expected_ret); + + /* BREAKPOINT_PROMPT */ + debug_service_exceptions = 0; + ret = func(2); + ok(debug_service_exceptions == expected_exc, + "BREAKPOINT_PROMPT generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret, + "BREAKPOINT_PROMPT returned %u, expected %u\n", ret, expected_ret); + + /* invalid debug service */ + debug_service_exceptions = 0; + ret = func(6); + ok(debug_service_exceptions == expected_exc, + "invalid debug service generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret, + "invalid debug service returned %u, expected %u\n", ret, expected_ret); + + expected_exc = (is_wow64 ? numexc : 0); + expected_ret = (is_wow64 && numexc); + + /* BREAKPOINT_PRINT */ + debug_service_exceptions = 0; + ret = func(1); + ok(debug_service_exceptions == expected_exc, + "BREAKPOINT_PRINT generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret, + "BREAKPOINT_PRINT returned %u, expected %u\n", ret, expected_ret); + + /* BREAKPOINT_LOAD_SYMBOLS */ + debug_service_exceptions = 0; + ret = func(3); + ok(debug_service_exceptions == expected_exc, + "BREAKPOINT_LOAD_SYMBOLS generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret, + "BREAKPOINT_LOAD_SYMBOLS returned %u, expected %u\n", ret, expected_ret); + + /* BREAKPOINT_UNLOAD_SYMBOLS */ + debug_service_exceptions = 0; + ret = func(4); + ok(debug_service_exceptions == expected_exc, + "BREAKPOINT_UNLOAD_SYMBOLS generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret, + "BREAKPOINT_UNLOAD_SYMBOLS returned %u, expected %u\n", ret, expected_ret); + + /* BREAKPOINT_COMMAND_STRING */ + debug_service_exceptions = 0; + ret = func(5); + ok(debug_service_exceptions == expected_exc || broken(debug_service_exceptions == numexc), + "BREAKPOINT_COMMAND_STRING generated %u exceptions, expected %u\n", + debug_service_exceptions, expected_exc); + ok(ret == expected_ret || broken(ret == (numexc != 0)), + "BREAKPOINT_COMMAND_STRING returned %u, expected %u\n", ret, expected_ret); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); +} + +static DWORD breakpoint_exceptions; + +static LONG CALLBACK breakpoint_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord; + trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress); + + ok(rec->ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode is %08x instead of %08x\n", + rec->ExceptionCode, EXCEPTION_BREAKPOINT); + +#ifdef __i386__ + ok(ExceptionInfo->ContextRecord->Eip == (DWORD)code_mem + 1, + "expected Eip = %x, got %x\n", (DWORD)code_mem + 1, ExceptionInfo->ContextRecord->Eip); + ok(rec->NumberParameters == (is_wow64 ? 1 : 3), + "ExceptionParameters is %d instead of %d\n", rec->NumberParameters, is_wow64 ? 1 : 3); + ok(rec->ExceptionInformation[0] == 0, + "got ExceptionInformation[0] = %lx\n", rec->ExceptionInformation[0]); + ExceptionInfo->ContextRecord->Eip = (DWORD)code_mem + 2; +#else + ok(ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)code_mem + 1, + "expected Rip = %lx, got %lx\n", (DWORD_PTR)code_mem + 1, ExceptionInfo->ContextRecord->Rip); + ok(rec->NumberParameters == 1, + "ExceptionParameters is %d instead of 1\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 0, + "got ExceptionInformation[0] = %lx\n", rec->ExceptionInformation[0]); + ExceptionInfo->ContextRecord->Rip = (DWORD_PTR)code_mem + 2; +#endif + + breakpoint_exceptions++; + return (rec->ExceptionCode == EXCEPTION_BREAKPOINT) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} + +static const BYTE breakpoint_code[] = { + 0xcd, 0x03, /* int $0x3 */ + 0xc3, /* ret */ +}; + +static void test_breakpoint(DWORD numexc) +{ + DWORD (CDECL *func)(void) = code_mem; + void *vectored_handler; + + memcpy(code_mem, breakpoint_code, sizeof(breakpoint_code)); + + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &breakpoint_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + + breakpoint_exceptions = 0; + func(); + ok(breakpoint_exceptions == numexc, "int $0x3 generated %u exceptions, expected %u\n", + breakpoint_exceptions, numexc); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); +} + static DWORD invalid_handle_exceptions;
static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) @@ -1893,6 +2675,10 @@ static void test_vectored_continue_handler(void) START_TEST(exception) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); +#if defined(__x86_64__) + HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll"); +#endif + #ifdef __REACTOS__ if (!winetest_interactive && !strcmp(winetest_platform, "windows")) @@ -1907,13 +2693,13 @@ START_TEST(exception) return; }
- pNtCurrentTeb = (void *)GetProcAddress( hntdll, "NtCurrentTeb" ); pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" ); pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" ); pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" ); pNtClose = (void *)GetProcAddress( hntdll, "NtClose" ); pRtlUnwind = (void *)GetProcAddress( hntdll, "RtlUnwind" ); pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" ); + pRtlCaptureContext = (void *)GetProcAddress( hntdll, "RtlCaptureContext" ); pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" ); pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" ); @@ -1930,11 +2716,6 @@ START_TEST(exception) pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
#ifdef __i386__ - if (!pNtCurrentTeb) - { - skip( "NtCurrentTeb not found\n" ); - return; - } if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler) @@ -1955,7 +2736,7 @@ START_TEST(exception) }
/* child must be run under a debugger */ - if (!pNtCurrentTeb()->Peb->BeingDebugged) + if (!NtCurrentTeb()->Peb->BeingDebugged) { ok(FALSE, "child process not being debugged?\n"); return; @@ -1980,8 +2761,16 @@ START_TEST(exception) test_stage = 6; test_ripevent(1); test_stage = 7; - test_closehandle(0); + test_debug_service(0); test_stage = 8; + test_debug_service(1); + test_stage = 9; + test_breakpoint(0); + test_stage = 10; + test_breakpoint(1); + test_stage = 11; + test_closehandle(0); + test_stage = 12; test_closehandle(1); } else @@ -1994,8 +2783,11 @@ START_TEST(exception) test_unwind(); test_exceptions(); test_rtlraiseexception(); + test_debug_registers(); test_outputdebugstring(1); test_ripevent(1); + test_debug_service(1); + test_breakpoint(1); test_closehandle(0); test_vectored_continue_handler(); test_debugger(); @@ -2003,6 +2795,7 @@ START_TEST(exception) test_fpu_exceptions(); test_dpe_exceptions(); test_prot_fault(); + test_thread_context();
#elif defined(__x86_64__) pRtlAddFunctionTable = (void *)GetProcAddress( hntdll, @@ -2013,12 +2806,27 @@ START_TEST(exception) "RtlInstallFunctionTableCallback" ); pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll, "RtlLookupFunctionEntry" ); - + p__C_specific_handler = (void *)GetProcAddress( hntdll, + "__C_specific_handler" ); + pRtlCaptureContext = (void *)GetProcAddress( hntdll, + "RtlCaptureContext" ); + pRtlRestoreContext = (void *)GetProcAddress( hntdll, + "RtlRestoreContext" ); + pRtlUnwindEx = (void *)GetProcAddress( hntdll, + "RtlUnwindEx" ); + p_setjmp = (void *)GetProcAddress( hmsvcrt, + "_setjmp" ); + + test_debug_registers(); test_outputdebugstring(1); test_ripevent(1); + test_debug_service(1); + test_breakpoint(1); test_closehandle(0); test_vectored_continue_handler(); test_virtual_unwind(); + test___C_specific_handler(); + test_restore_context();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry) test_dynamic_unwind(); @@ -2027,5 +2835,5 @@ START_TEST(exception)
#endif
- VirtualFree(code_mem, 0, MEM_FREE); + VirtualFree(code_mem, 0, MEM_RELEASE); } diff --git a/modules/rostests/winetests/ntdll/file.c b/modules/rostests/winetests/ntdll/file.c index 0387398e5d..3316399c2f 100644 --- a/modules/rostests/winetests/ntdll/file.c +++ b/modules/rostests/winetests/ntdll/file.c @@ -94,6 +94,7 @@ static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent, static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE hFile, PIO_STATUS_BLOCK io_status); static NTSTATUS (WINAPI *pNtCancelIoFileEx)(HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status); static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); +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 *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); @@ -106,6 +107,7 @@ static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PV PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN); static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS); static NTSTATUS (WINAPI *pNtQueryFullAttributesFile)(const OBJECT_ATTRIBUTES*, FILE_NETWORK_OPEN_INFORMATION*); +static NTSTATUS (WINAPI *pNtFlushBuffersFile)(HANDLE, IO_STATUS_BLOCK*); static NTSTATUS (WINAPI *pNtQueryEaFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,BOOLEAN,PVOID,ULONG,PULONG,BOOLEAN);
static inline BOOL is_signaled( HANDLE obj ) @@ -113,31 +115,8 @@ static inline BOOL is_signaled( HANDLE obj ) return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0; }
-static const char* debugstr_longlong(ULONGLONG ll) -{ - static char str[17]; - if (sizeof(ll) > sizeof(unsigned long) && ll >> 32) - sprintf(str, "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll); - else - sprintf(str, "%lx", (unsigned long)ll); - return str; -} - -#define PIPENAME "\\.\pipe\ntdll_tests_file.c" #define TEST_BUF_LEN 3
-static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size ) -{ - *read = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT, - 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL); - ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); - - *write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); - - return TRUE; -} - static HANDLE create_temp_file( ULONG flags ) { char path[MAX_PATH], buffer[MAX_PATH]; @@ -198,18 +177,22 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
static void create_file_test(void) { + static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0}; 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 systemrootExplorerW[] = {'\','S','y','s','t','e','m','R','o','o','t', + '\','e','x','p','l','o','r','e','r','.','e','x','e',0}; static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0}; static const WCHAR pipeInvalidNameW[] = {'a','|','b',0}; static const WCHAR pathInvalidNtW[] = {'\','\','?','\',0}; static const WCHAR pathInvalidNt2W[] = {'\','?','?','\',0}; static const WCHAR pathInvalidDosW[] = {'\','D','o','s','D','e','v','i','c','e','s','\',0}; static const char testdata[] = "Hello World"; + static const WCHAR sepW[] = {'\',0}; FILE_NETWORK_OPEN_INFORMATION info; NTSTATUS status; HANDLE dir, file; - WCHAR path[MAX_PATH]; + WCHAR path[MAX_PATH], temp[MAX_PATH]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; UNICODE_STRING nameW; @@ -389,6 +372,25 @@ static void create_file_test(void) status = pNtQueryFullAttributesFile( &attr, &info ); ok( status == STATUS_OBJECT_NAME_INVALID, "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + GetWindowsDirectoryW( path, MAX_PATH ); + path[2] = 0; + ok( QueryDosDeviceW( path, temp, MAX_PATH ), + "QueryDosDeviceW failed with error %u\n", GetLastError() ); + lstrcatW( temp, sepW ); + lstrcatW( temp, path+3 ); + lstrcatW( temp, sepW ); + lstrcatW( temp, notepadW ); + + pRtlInitUnicodeString( &nameW, temp ); + status = pNtQueryFullAttributesFile( &attr, &info ); + ok( status == STATUS_SUCCESS, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + pRtlInitUnicodeString( &nameW, systemrootExplorerW ); + status = pNtQueryFullAttributesFile( &attr, &info ); + ok( status == STATUS_SUCCESS, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); }
static void open_file_test(void) @@ -660,268 +662,14 @@ static void delete_file_test(void) static void read_file_test(void) { const char text[] = "foobar"; - HANDLE handle, read, write; + HANDLE handle; + IO_STATUS_BLOCK iosb; NTSTATUS status; - IO_STATUS_BLOCK iosb, iosb2; - DWORD written; int apc_count = 0; char buffer[128]; LARGE_INTEGER offset; HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL ); - BOOL ret; - - buffer[0] = 1; - - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - - /* try read with no data */ - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ok( is_signaled( read ), "read handle is not signaled\n" ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( read ), "read handle is signaled\n" ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - /* iosb updated here by async i/o */ - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( !is_signaled( read ), "read handle is signaled\n" ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - apc_count = 0; - SleepEx( 1, FALSE ); /* non-alertable sleep */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc not called\n" ); - - /* with no event, the pipe handle itself gets signaled */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ok( !is_signaled( read ), "read handle is signaled\n" ); - status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( read ), "read handle is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - /* iosb updated here by async i/o */ - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( read ), "read handle is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - apc_count = 0; - SleepEx( 1, FALSE ); /* non-alertable sleep */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc not called\n" );
- /* now read with data ready */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ResetEvent( event ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, FALSE ); /* non-alertable sleep */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc not called\n" ); - - /* try read with no data */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */ - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - ret = WriteFile( write, buffer, 1, &written, NULL ); - ok(ret && written == 1, "WriteFile error %d\n", GetLastError()); - /* partial read is good enough */ - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( is_signaled( event ), "event is not signaled\n" ); - ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - - /* read from disconnected pipe */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - CloseHandle( write ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( !apc_count, "apc was called\n" ); - CloseHandle( read ); - - /* read from closed handle */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - SetEvent( event ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL ); - ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on invalid handle */ - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( !apc_count, "apc was called\n" ); - - /* disconnect while async read is in progress */ - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - CloseHandle( write ); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - CloseHandle( read ); - - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - 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; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - /* Cancel by other handle */ - status = pNtCancelIoFile( read, &iosb2 ); - ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - /* Close queued handle */ - CloseHandle( read ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - status = pNtCancelIoFile( read, &iosb2 ); - ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n"); - status = pNtCancelIoFile( handle, &iosb2 ); - ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - CloseHandle( handle ); - CloseHandle( write ); - - if (pNtCancelIoFileEx) - { - /* Basic Cancel Ex */ - if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return; - - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); - ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 1, "apc was not called\n" ); - - /* Duplicate iosb */ - apc_count = 0; - U(iosb).Status = 0xdeadbabe; - iosb.Information = 0xdeadbeef; - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL ); - ok( status == STATUS_PENDING, "wrong status %x\n", status ); - ok( !is_signaled( event ), "event is signaled\n" ); - ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information ); - ok( !apc_count, "apc was called\n" ); - status = pNtCancelIoFileEx( read, &iosb, &iosb2 ); - ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n"); - Sleep(1); /* FIXME: needed for wine to run the i/o apc */ - ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status ); - ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information ); - ok( is_signaled( event ), "event is not signaled\n" ); - ok( !apc_count, "apc was called\n" ); - SleepEx( 1, TRUE ); /* alertable sleep */ - ok( apc_count == 2, "apc was not called\n" ); - - CloseHandle( read ); - CloseHandle( write ); - } - - /* now try a real file */ if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return; apc_count = 0; U(iosb).Status = 0xdeadbabe; @@ -1297,7 +1045,7 @@ static void test_iocp_fileio(HANDLE h) ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey ); ok( ioSb.Information == 0, "Invalid ioSb.Information: %ld\n", ioSb.Information ); /* wine sends wrong status here */ - todo_wine ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status); + ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status); ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue ); } } @@ -1315,6 +1063,7 @@ static void test_iocp_fileio(HANDLE h) { OVERLAPPED o = {0,}; BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN]; + int apc_count = 0; DWORD read; long count;
@@ -1343,6 +1092,58 @@ static void test_iocp_fileio(HANDLE h) } count = get_pending_msgs(h); ok( !count, "Unexpected msg count: %ld\n", count ); + + /* using APCs on handle with associated completion port is not allowed */ + res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf, sizeof(recv_buf), NULL, NULL ); + ok(res == STATUS_INVALID_PARAMETER, "NtReadFile returned %x\n", res); + } + + CloseHandle( hPipeSrv ); + CloseHandle( hPipeClt ); + + /* test associating a completion port with a handle after an async using APC is queued */ + hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL ); + ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" ); + if (hPipeSrv == INVALID_HANDLE_VALUE ) + return; + hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL ); + ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" ); + if (hPipeClt != INVALID_HANDLE_VALUE) + { + BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN]; + int apc_count = 0; + DWORD read; + long count; + + memset( send_buf, 0, TEST_BUF_LEN ); + memset( recv_buf, 0xde, TEST_BUF_LEN ); + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + + res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf, sizeof(recv_buf), NULL, NULL ); + ok(res == STATUS_PENDING, "NtReadFile returned %x\n", res); + + 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 ); + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + + WriteFile( hPipeClt, send_buf, TEST_BUF_LEN, &read, NULL ); + + ok(!apc_count, "apc_count = %u\n", apc_count); + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + + SleepEx(1, TRUE); /* alertable sleep */ + ok(apc_count == 1, "apc was not called\n"); + count = get_pending_msgs(h); + ok( !count, "Unexpected msg count: %ld\n", count ); + + /* using APCs on handle with associated completion port is not allowed */ + res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf, sizeof(recv_buf), NULL, NULL ); + ok(res == STATUS_INVALID_PARAMETER, "NtReadFile returned %x\n", res); }
CloseHandle( hPipeSrv ); @@ -1371,10 +1172,10 @@ static void test_file_full_size_information(void) /* Test for FileFsSizeInformation */ ok(fsi.TotalAllocationUnits.QuadPart > 0, "[fsi] TotalAllocationUnits expected positive, got 0x%s\n", - debugstr_longlong(fsi.TotalAllocationUnits.QuadPart)); + wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart)); ok(fsi.AvailableAllocationUnits.QuadPart > 0, "[fsi] AvailableAllocationUnits expected positive, got 0x%s\n", - debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart)); + wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart));
/* Assume file system is NTFS */ ok(fsi.BytesPerSector == 512, "[fsi] BytesPerSector expected 512, got %d\n",fsi.BytesPerSector); @@ -1382,21 +1183,21 @@ static void test_file_full_size_information(void)
ok(ffsi.TotalAllocationUnits.QuadPart > 0, "[ffsi] TotalAllocationUnits expected positive, got negative value 0x%s\n", - debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart)); + wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart)); ok(ffsi.CallerAvailableAllocationUnits.QuadPart > 0, "[ffsi] CallerAvailableAllocationUnits expected positive, got negative value 0x%s\n", - debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart)); + wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart)); ok(ffsi.ActualAvailableAllocationUnits.QuadPart > 0, "[ffsi] ActualAvailableAllocationUnits expected positive, got negative value 0x%s\n", - debugstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart)); + wine_dbgstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart)); ok(ffsi.TotalAllocationUnits.QuadPart == fsi.TotalAllocationUnits.QuadPart, "[ffsi] TotalAllocationUnits error fsi:0x%s, ffsi:0x%s\n", - debugstr_longlong(fsi.TotalAllocationUnits.QuadPart), - debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart)); + wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart), + wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart)); ok(ffsi.CallerAvailableAllocationUnits.QuadPart == fsi.AvailableAllocationUnits.QuadPart, "[ffsi] CallerAvailableAllocationUnits error fsi:0x%s, ffsi: 0x%s\n", - debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart), - debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart)); + wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart), + wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
/* Assume file system is NTFS */ ok(ffsi.BytesPerSector == 512, "[ffsi] BytesPerSector expected 512, got %d\n",ffsi.BytesPerSector); @@ -1592,7 +1393,7 @@ static void test_file_rename_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", + ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni );
@@ -1762,7 +1563,7 @@ static void test_file_rename_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", + ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni );
@@ -2168,7 +1969,7 @@ static void test_file_rename_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", + ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni );
@@ -2181,6 +1982,7 @@ static void test_file_rename_information(void)
static void test_file_link_information(void) { + static const WCHAR pipeW[] = {'\','\','.','\','p','i','p','e','\','w','i','n','e','_','t','e','s','t',0}; static const WCHAR foo_txtW[] = {'\','f','o','o','.','t','x','t',0}; static const WCHAR fooW[] = {'f','o','o',0}; WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p; @@ -2224,7 +2026,7 @@ static void test_file_link_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", + ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni );
@@ -2394,7 +2196,7 @@ static void test_file_link_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", + ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni );
@@ -2797,12 +2599,36 @@ static void test_file_link_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", + ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni );
CloseHandle( handle ); CloseHandle( handle2 ); + + handle = CreateEventA( NULL, FALSE, FALSE, "wine_test_event" ); + ok( !!handle, "Failed to create event: %u\n", GetLastError()); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_OBJECT_TYPE_MISMATCH, "res expected STATUS_OBJECT_TYPE_MISMATCH, got %x\n", res ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + + handle = CreateNamedPipeW( pipeW, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 10, 512, 512, 0, NULL); + ok( handle != INVALID_HANDLE_VALUE, "Failed to create named pipe: %u\n", GetLastError()); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpiW(fni->FileName, pipeW + 8), "FileName expected %s, got %s\n", + wine_dbgstr_w(pipeW + 8), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); delete_object( oldpath ); delete_object( newpath ); @@ -3349,6 +3175,213 @@ static void test_file_all_name_information(void) HeapFree( GetProcessHeap(), 0, file_name ); }
+static void test_file_completion_information(void) +{ + static const char buf[] = "testdata"; + FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; + OVERLAPPED ov, *pov; + IO_STATUS_BLOCK io; + NTSTATUS status; + DWORD num_bytes; + HANDLE port, h; + ULONG_PTR key; + BOOL ret; + int i; + + if (!(h = create_temp_file(0))) return; + + status = pNtSetInformationFile(h, &io, &info, sizeof(info) - 1, FileIoCompletionNotificationInformation); + ok(status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_INFO_CLASS /* XP */, + "expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED) + { + win_skip("FileIoCompletionNotificationInformation class not supported\n"); + CloseHandle(h); + return; + } + + info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %08x\n", status); + + CloseHandle(h); + if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return; + + info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + + info.Flags = FILE_SKIP_SET_USER_EVENT_ON_FAST_IO; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + + CloseHandle(h); + if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return; + + info.Flags = ~0U; + status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok(!(info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS), "got %08x\n", info.Flags); + + memset(&ov, 0, sizeof(ov)); + ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + port = CreateIoCompletionPort(h, NULL, 0xdeadbeef, 0); + ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError()); + + for (i = 0; i < 10; i++) + { + SetLastError(0xdeadbeef); + ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov); + if (ret || GetLastError() != ERROR_IO_PENDING) break; + ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE); + ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError()); + ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); + ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError()); + ret = FALSE; + } + if (ret) + { + ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); + + key = 0; + pov = NULL; + ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); + ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError()); + ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key); + ok(pov == &ov, "expected %p, got %p\n", &ov, pov); + } + else + win_skip("WriteFile never returned TRUE\n"); + + info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + + info.Flags = 0; + status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags); + + for (i = 0; i < 10; i++) + { + SetLastError(0xdeadbeef); + ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov); + if (ret || GetLastError() != ERROR_IO_PENDING) break; + ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE); + ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError()); + ret = FALSE; + } + if (ret) + { + ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); + + pov = (void *)0xdeadbeef; + ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 500); + ok(!ret, "GetQueuedCompletionStatus succeeded\n"); + ok(pov == NULL, "expected NULL, got %p\n", pov); + } + else + win_skip("WriteFile never returned TRUE\n"); + + info.Flags = 0; + status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + + info.Flags = 0; + status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags); + + for (i = 0; i < 10; i++) + { + SetLastError(0xdeadbeef); + ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov); + if (ret || GetLastError() != ERROR_IO_PENDING) break; + ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE); + ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError()); + ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); + ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError()); + ret = FALSE; + } + if (ret) + { + ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); + + pov = (void *)0xdeadbeef; + ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); + ok(!ret, "GetQueuedCompletionStatus succeeded\n"); + ok(pov == NULL, "expected NULL, got %p\n", pov); + } + else + win_skip("WriteFile never returned TRUE\n"); + + CloseHandle(ov.hEvent); + CloseHandle(port); + CloseHandle(h); +} + +static void test_file_id_information(void) +{ + BY_HANDLE_FILE_INFORMATION info; + FILE_ID_INFORMATION fid; + IO_STATUS_BLOCK io; + NTSTATUS status; + DWORD *dwords; + HANDLE h; + BOOL ret; + + if (!(h = create_temp_file(0))) return; + + memset( &fid, 0x11, sizeof(fid) ); + status = pNtQueryInformationFile( h, &io, &fid, sizeof(fid), FileIdInformation ); + if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS) + { + win_skip( "FileIdInformation not supported\n" ); + CloseHandle( h ); + return; + } + + memset( &info, 0x22, sizeof(info) ); + ret = GetFileInformationByHandle( h, &info ); + ok( ret, "GetFileInformationByHandle failed\n" ); + + dwords = (DWORD *)&fid.VolumeSerialNumber; + ok( dwords[0] == info.dwVolumeSerialNumber, "expected %08x, got %08x\n", + info.dwVolumeSerialNumber, dwords[0] ); + ok( dwords[1] != 0x11111111, "expected != 0x11111111\n" ); + + dwords = (DWORD *)&fid.FileId; + ok( dwords[0] == info.nFileIndexLow, "expected %08x, got %08x\n", info.nFileIndexLow, dwords[0] ); + ok( dwords[1] == info.nFileIndexHigh, "expected %08x, got %08x\n", info.nFileIndexHigh, dwords[1] ); + ok( dwords[2] == 0, "expected 0, got %08x\n", dwords[2] ); + ok( dwords[3] == 0, "expected 0, got %08x\n", dwords[3] ); + + CloseHandle( h ); +} + +static void test_file_access_information(void) +{ + FILE_ACCESS_INFORMATION info; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE h; + + if (!(h = create_temp_file(0))) return; + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info) - 1, FileAccessInformation ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status ); + + status = pNtQueryInformationFile( (HANDLE)0xdeadbeef, &io, &info, sizeof(info), FileAccessInformation ); + ok( status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08x\n", status ); + + memset(&info, 0x11, sizeof(info)); + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileAccessInformation ); + ok( status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status ); + ok( info.AccessFlags == 0x13019f, "got %08x\n", info.AccessFlags ); + + CloseHandle( h ); +} + static void test_query_volume_information_file(void) { NTSTATUS status; @@ -3616,13 +3649,15 @@ static void test_read_write(void) { static const char contents[14] = "1234567890abcd"; char buf[256]; - HANDLE hfile; + HANDLE hfile, event; OVERLAPPED ovl; IO_STATUS_BLOCK iob; DWORD ret, bytes, status, off; LARGE_INTEGER offset; LONG i;
+ event = CreateEventA( NULL, TRUE, FALSE, NULL ); + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; @@ -3631,6 +3666,22 @@ static void test_read_write(void) ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = 0; + status = pNtReadFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, NULL, sizeof(buf), &offset, NULL); + ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, "expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); + + U(iob).Status = -1; + iob.Information = -1; + offset.QuadPart = 0; + status = pNtWriteFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL); + ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, "expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); + U(iob).Status = -1; iob.Information = -1; offset.QuadPart = 0; @@ -3649,6 +3700,15 @@ static void test_read_write(void) ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ U(iob).Status = -1; + iob.Information = -1; + SetEvent(event); + status = pNtWriteFile(hfile, event, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL); + ok(status == STATUS_INVALID_USER_BUFFER, "expected STATUS_INVALID_USER_BUFFER, got %#x\n", status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); + ok(!is_signaled(event), "event is not signaled\n"); + U(iob).Status = -1; iob.Information = -1; status = pNtReadFile(hfile, 0, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL); @@ -3656,6 +3716,24 @@ static void test_read_write(void) ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ U(iob).Status = -1; + iob.Information = -1; + SetEvent(event); + status = pNtReadFile(hfile, event, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL); + ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); + ok(is_signaled(event), "event is not signaled\n"); + + U(iob).Status = -1; + iob.Information = -1; + SetEvent(event); + status = pNtReadFile(hfile, event, NULL, NULL, &iob, (void*)0xdeadbeef, sizeof(contents), NULL, NULL); + ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status); + ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status); + ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information); + ok(is_signaled(event), "event is not signaled\n"); + U(iob).Status = -1; iob.Information = -1; status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, 7, NULL, NULL); @@ -4321,7 +4399,78 @@ static void test_read_write(void) off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT); ok(off == 0, "expected 0, got %u\n", off);
+ CloseHandle(event); + CloseHandle(hfile); +} + +static void test_ioctl(void) +{ + HANDLE event = CreateEventA(NULL, TRUE, FALSE, NULL); + IO_STATUS_BLOCK iosb; + HANDLE file; + NTSTATUS status; + + file = create_temp_file(FILE_FLAG_OVERLAPPED); + ok(file != INVALID_HANDLE_VALUE, "could not create temp file\n"); + + SetEvent(event); + status = pNtFsControlFile(file, event, NULL, NULL, &iosb, 0xdeadbeef, 0, 0, 0, 0); + todo_wine + ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtFsControlFile returned %x\n", status); + ok(!is_signaled(event), "event is signaled\n"); + + status = pNtFsControlFile(file, (HANDLE)0xdeadbeef, NULL, NULL, &iosb, 0xdeadbeef, 0, 0, 0, 0); + ok(status == STATUS_INVALID_HANDLE, "NtFsControlFile returned %x\n", status); + + CloseHandle(event); + CloseHandle(file); +} + +static void test_flush_buffers_file(void) +{ + char path[MAX_PATH], buffer[MAX_PATH]; + HANDLE hfile, hfileread; + NTSTATUS status; + IO_STATUS_BLOCK io_status_block; + + GetTempPathA(MAX_PATH, path); + GetTempFileNameA(path, "foo", 0, buffer); + hfile = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + ok(hfile != INVALID_HANDLE_VALUE, "failed to create temp file.\n" ); + + hfileread = CreateFileA(buffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + ok(hfileread != INVALID_HANDLE_VALUE, "could not open temp file, error %d.\n", GetLastError()); + + status = pNtFlushBuffersFile(hfile, NULL); + todo_wine + ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + + status = pNtFlushBuffersFile(hfile, (IO_STATUS_BLOCK *)0xdeadbeaf); + todo_wine + ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + + status = pNtFlushBuffersFile(hfile, &io_status_block); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x.\n", status); + + status = pNtFlushBuffersFile(hfileread, &io_status_block); + ok(status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got %#x.\n", status); + + status = pNtFlushBuffersFile(NULL, &io_status_block); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %#x.\n", status); + + CloseHandle(hfileread); CloseHandle(hfile); + hfile = CreateFileA(buffer, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "could not open temp file, error %d.\n", GetLastError()); + + status = pNtFlushBuffersFile(hfile, &io_status_block); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x.\n", status); + + CloseHandle(hfile); + DeleteFileA(buffer); }
static void test_query_ea(void) @@ -4601,6 +4750,7 @@ START_TEST(file) pNtCancelIoFile = (void *)GetProcAddress(hntdll, "NtCancelIoFile"); pNtCancelIoFileEx = (void *)GetProcAddress(hntdll, "NtCancelIoFileEx"); pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); + pNtFsControlFile = (void *)GetProcAddress(hntdll, "NtFsControlFile"); pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); pNtQueryIoCompletion = (void *)GetProcAddress(hntdll, "NtQueryIoCompletion"); @@ -4611,6 +4761,7 @@ START_TEST(file) pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll, "NtQueryVolumeInformationFile"); pNtQueryFullAttributesFile = (void *)GetProcAddress(hntdll, "NtQueryFullAttributesFile"); + pNtFlushBuffersFile = (void *)GetProcAddress(hntdll, "NtFlushBuffersFile"); pNtQueryEaFile = (void *)GetProcAddress(hntdll, "NtQueryEaFile");
test_read_write(); @@ -4632,8 +4783,13 @@ START_TEST(file) test_file_rename_information(); test_file_link_information(); test_file_disposition_information(); + test_file_completion_information(); + test_file_id_information(); + test_file_access_information(); test_query_volume_information_file(); test_query_attribute_information_file(); + test_ioctl(); + test_flush_buffers_file(); test_query_ea(); test_junction_points(); } diff --git a/modules/rostests/winetests/ntdll/info.c b/modules/rostests/winetests/ntdll/info.c index c0e2b1ac5d..d03d26c0b9 100755 --- a/modules/rostests/winetests/ntdll/info.c +++ b/modules/rostests/winetests/ntdll/info.c @@ -22,7 +22,9 @@ #include <winnls.h> #include <stdio.h>
+static NTSTATUS (WINAPI * pRtlDowncaseUnicodeString)(UNICODE_STRING *, const UNICODE_STRING *, BOOLEAN); static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +static NTSTATUS (WINAPI * pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*); static NTSTATUS (WINAPI * pNtPowerInformation)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG); static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); static NTSTATUS (WINAPI * pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG); @@ -36,6 +38,7 @@ static NTSTATUS (WINAPI * pNtUnmapViewOfSection)(HANDLE,PVOID); static NTSTATUS (WINAPI * pNtClose)(HANDLE); static ULONG (WINAPI * pNtGetCurrentProcessorNumber)(void); static BOOL (WINAPI * pIsWow64Process)(HANDLE, PBOOL); +static BOOL (WINAPI * pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
static BOOL is_wow64;
@@ -56,12 +59,15 @@ static BOOL InitFunctionPtrs(void) { /* All needed functions are NT based, so using GetModuleHandle is a good check */ HMODULE hntdll = GetModuleHandleA("ntdll"); + HMODULE hkernel32 = GetModuleHandleA("kernel32"); + if (!hntdll) { win_skip("Not running on NT\n"); return FALSE; }
+ NTDLL_GET_PROC(RtlDowncaseUnicodeString); NTDLL_GET_PROC(NtQuerySystemInformation); NTDLL_GET_PROC(NtPowerInformation); NTDLL_GET_PROC(NtQueryInformationProcess); @@ -78,8 +84,16 @@ static BOOL InitFunctionPtrs(void) /* not present before XP */ pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll, "NtGetCurrentProcessorNumber");
- pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); + pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process"); if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; + + /* starting with Win7 */ + pNtQuerySystemInformationEx = (void *) GetProcAddress(hntdll, "NtQuerySystemInformationEx"); + if (!pNtQuerySystemInformationEx) + win_skip("NtQuerySystemInformationEx() is not supported, some tests will be skipped.\n"); + + pGetLogicalProcessorInformationEx = (void *) GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx"); + return TRUE; }
@@ -288,7 +302,7 @@ static void test_query_process(void) /* test ReturnLength */ ReturnLength = 0; status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ReturnLength); - ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_LENGTH_MISMATCH got %08x\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH got %08x\n", status); ok( ReturnLength > 0 || broken(ReturnLength == 0) /* NT4, Win2K */, "Expected a ReturnLength to show the needed length\n");
@@ -474,13 +488,15 @@ static void test_query_module(void) static void test_query_handle(void) { NTSTATUS status; - ULONG ReturnLength; + ULONG ExpectedLength, ReturnLength; ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION); SYSTEM_HANDLE_INFORMATION* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); - HANDLE event_handle; + HANDLE EventHandle; + BOOL found; + INT i;
- event_handle = CreateEventA(NULL, FALSE, FALSE, NULL); - ok( event_handle != NULL, "CreateEventA failed %u\n", GetLastError() ); + EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL); + ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() );
/* Request the needed length : a SystemInformationLength greater than one struct sets ReturnLength */ ReturnLength = 0xdeadbeef; @@ -490,34 +506,116 @@ static void test_query_handle(void)
SystemInformationLength = ReturnLength; shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength); + memset(shi, 0x55, SystemInformationLength);
ReturnLength = 0xdeadbeef; status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); - if (status != STATUS_INFO_LENGTH_MISMATCH) /* vista */ + while (status == STATUS_INFO_LENGTH_MISMATCH) /* Vista / 2008 */ { - ULONG ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]); - unsigned int i; - BOOL found = FALSE; + SystemInformationLength *= 2; + shi = HeapReAlloc(GetProcessHeap(), 0, shi, SystemInformationLength); + memset(shi, 0x55, SystemInformationLength); + status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); + } + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); + ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]); + ok( ReturnLength == ExpectedLength || broken(ReturnLength == ExpectedLength - sizeof(DWORD)), /* Vista / 2008 */ + "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); + ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", shi->Count ); + ok( shi->Handle[1].HandleValue != 0x5555 || broken( shi->Handle[1].HandleValue == 0x5555 ), /* Vista / 2008 */ + "Uninitialized second handle\n" ); + if (shi->Handle[1].HandleValue == 0x5555) + { + win_skip("Skipping broken SYSTEM_HANDLE_INFORMATION\n"); + CloseHandle(EventHandle); + goto done; + } + + for (i = 0, found = FALSE; i < shi->Count && !found; i++) + found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) && + ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); + ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() );
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); - ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); - ok( shi->Count > 1, "Expected more than 1 handles, got %u\n", shi->Count ); + if (!found) for (i = 0; i < shi->Count; i++) - { - if (shi->Handle[i].OwnerPid == GetCurrentProcessId() && - (HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == event_handle) - { - found = TRUE; - break; - } - } - ok( found, "Expected to find event handle in handle list\n" ); + trace( "%d: handle %x pid %x\n", i, shi->Handle[i].HandleValue, shi->Handle[i].OwnerPid ); + + CloseHandle(EventHandle); + + ReturnLength = 0xdeadbeef; + status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); + while (status == STATUS_INFO_LENGTH_MISMATCH) /* Vista / 2008 */ + { + SystemInformationLength *= 2; + shi = HeapReAlloc(GetProcessHeap(), 0, shi, SystemInformationLength); + status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); } + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); + for (i = 0, found = FALSE; i < shi->Count && !found; i++) + found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) && + ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); + ok( !found, "Unexpectedly found event handle in handle list\n" );
status = pNtQuerySystemInformation(SystemHandleInformation, NULL, SystemInformationLength, &ReturnLength); ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status );
- CloseHandle(event_handle); +done: + HeapFree( GetProcessHeap(), 0, shi); +} + +static void test_query_handle_ex(void) +{ + NTSTATUS status; + ULONG ExpectedLength, ReturnLength; + ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION_EX); + SYSTEM_HANDLE_INFORMATION_EX* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); + HANDLE EventHandle; + BOOL found; + INT i; + + EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL); + ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() ); + + ReturnLength = 0xdeadbeef; + status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( ReturnLength != 0xdeadbeef, "Expected valid ReturnLength\n" ); + + SystemInformationLength = ReturnLength; + shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength); + memset(shi, 0x55, SystemInformationLength); + + ReturnLength = 0xdeadbeef; + status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); + ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle[shi->Count]); + ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); + ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", (DWORD)shi->Count ); + + for (i = 0, found = FALSE; i < shi->Count && !found; i++) + found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) && + ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); + ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() ); + + if (!found) + { + for (i = 0; i < shi->Count; i++) + trace( "%d: handle %x pid %x\n", i, (DWORD)shi->Handle[i].HandleValue, (DWORD)shi->Handle[i].UniqueProcessId ); + } + + CloseHandle(EventHandle); + + ReturnLength = 0xdeadbeef; + status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); + for (i = 0, found = FALSE; i < shi->Count && !found; i++) + found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) && + ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); + ok( !found, "Unexpectedly found event handle in handle list\n" ); + + status = pNtQuerySystemInformation(SystemExtendedHandleInformation, NULL, SystemInformationLength, &ReturnLength); + ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status ); + HeapFree( GetProcessHeap(), 0, shi); }
@@ -684,6 +782,110 @@ static void test_query_logicalproc(void) HeapFree(GetProcessHeap(), 0, slpi); }
+static void test_query_logicalprocex(void) +{ + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infoex, *infoex2; + DWORD relationship, len2, len; + NTSTATUS status; + BOOL ret; + + if (!pNtQuerySystemInformationEx) + return; + + len = 0; + relationship = RelationProcessorCore; + status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status); + ok(len > 0, "got %u\n", len); + + len = 0; + relationship = RelationAll; + status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status); + ok(len > 0, "got %u\n", len); + + len2 = 0; + ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len2); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError()); + ok(len == len2, "got %u, expected %u\n", len2, len); + + if (len && len == len2) { + int j, i; + + infoex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); + infoex2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); + + status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), infoex, len, &len); + ok(status == STATUS_SUCCESS, "got 0x%08x\n", status); + + ret = pGetLogicalProcessorInformationEx(RelationAll, infoex2, &len2); + ok(ret, "got %d, error %d\n", ret, GetLastError()); + ok(!memcmp(infoex, infoex2, len), "returned info data mismatch\n"); + + for(i = 0; status == STATUS_SUCCESS && i < len; ){ + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ex = (void*)(((char *)infoex) + i); + + ok(ex->Relationship >= RelationProcessorCore && ex->Relationship <= RelationGroup, + "Got invalid relationship value: 0x%x\n", ex->Relationship); + if (!ex->Size) + { + ok(0, "got infoex[%u].Size=0\n", i); + break; + } + + trace("infoex[%u].Size: %u\n", i, ex->Size); + switch(ex->Relationship){ + case RelationProcessorCore: + case RelationProcessorPackage: + trace("infoex[%u].Relationship: 0x%x (Core == 0x0 or Package == 0x3)\n", i, ex->Relationship); + trace("infoex[%u].Processor.Flags: 0x%x\n", i, ex->Processor.Flags); +#ifndef __REACTOS__ + trace("infoex[%u].Processor.EfficiencyClass: 0x%x\n", i, ex->Processor.EfficiencyClass); +#endif + trace("infoex[%u].Processor.GroupCount: 0x%x\n", i, ex->Processor.GroupCount); + for(j = 0; j < ex->Processor.GroupCount; ++j){ + trace("infoex[%u].Processor.GroupMask[%u].Mask: 0x%lx\n", i, j, ex->Processor.GroupMask[j].Mask); + trace("infoex[%u].Processor.GroupMask[%u].Group: 0x%x\n", i, j, ex->Processor.GroupMask[j].Group); + } + break; + case RelationNumaNode: + trace("infoex[%u].Relationship: 0x%x (NumaNode)\n", i, ex->Relationship); + trace("infoex[%u].NumaNode.NodeNumber: 0x%x\n", i, ex->NumaNode.NodeNumber); + trace("infoex[%u].NumaNode.GroupMask.Mask: 0x%lx\n", i, ex->NumaNode.GroupMask.Mask); + trace("infoex[%u].NumaNode.GroupMask.Group: 0x%x\n", i, ex->NumaNode.GroupMask.Group); + break; + case RelationCache: + trace("infoex[%u].Relationship: 0x%x (Cache)\n", i, ex->Relationship); + trace("infoex[%u].Cache.Level: 0x%x\n", i, ex->Cache.Level); + trace("infoex[%u].Cache.Associativity: 0x%x\n", i, ex->Cache.Associativity); + trace("infoex[%u].Cache.LineSize: 0x%x\n", i, ex->Cache.LineSize); + trace("infoex[%u].Cache.CacheSize: 0x%x\n", i, ex->Cache.CacheSize); + trace("infoex[%u].Cache.Type: 0x%x\n", i, ex->Cache.Type); + trace("infoex[%u].Cache.GroupMask.Mask: 0x%lx\n", i, ex->Cache.GroupMask.Mask); + trace("infoex[%u].Cache.GroupMask.Group: 0x%x\n", i, ex->Cache.GroupMask.Group); + break; + case RelationGroup: + trace("infoex[%u].Relationship: 0x%x (Group)\n", i, ex->Relationship); + trace("infoex[%u].Group.MaximumGroupCount: 0x%x\n", i, ex->Group.MaximumGroupCount); + trace("infoex[%u].Group.ActiveGroupCount: 0x%x\n", i, ex->Group.ActiveGroupCount); + for(j = 0; j < ex->Group.ActiveGroupCount; ++j){ + trace("infoex[%u].Group.GroupInfo[%u].MaximumProcessorCount: 0x%x\n", i, j, ex->Group.GroupInfo[j].MaximumProcessorCount); + trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorCount: 0x%x\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorCount); + trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorMask: 0x%lx\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorMask); + } + break; + default: + break; + } + + i += ex->Size; + } + + HeapFree(GetProcessHeap(), 0, infoex); + HeapFree(GetProcessHeap(), 0, infoex2); + } +} + static void test_query_processor_power_info(void) { NTSTATUS status; @@ -904,12 +1106,32 @@ static void test_query_process_basic(void) ok( pbi.UniqueProcessId > 0, "Expected a ProcessID > 0, got 0\n"); }
+static void dump_vm_counters(const char *header, const VM_COUNTERS *pvi) +{ + trace("%s:\n", header); + trace("PeakVirtualSize : %lu\n", pvi->PeakVirtualSize); + trace("VirtualSize : %lu\n", pvi->VirtualSize); + trace("PageFaultCount : %u\n", pvi->PageFaultCount); + trace("PeakWorkingSetSize : %lu\n", pvi->PeakWorkingSetSize); + trace("WorkingSetSize : %lu\n", pvi->WorkingSetSize); + trace("QuotaPeakPagedPoolUsage : %lu\n", pvi->QuotaPeakPagedPoolUsage); + trace("QuotaPagedPoolUsage : %lu\n", pvi->QuotaPagedPoolUsage); + trace("QuotaPeakNonPagePoolUsage : %lu\n", pvi->QuotaPeakNonPagedPoolUsage); + trace("QuotaNonPagePoolUsage : %lu\n", pvi->QuotaNonPagedPoolUsage); + trace("PagefileUsage : %lu\n", pvi->PagefileUsage); + trace("PeakPagefileUsage : %lu\n", pvi->PeakPagefileUsage); +} + static void test_query_process_vm(void) { NTSTATUS status; ULONG ReturnLength; VM_COUNTERS pvi; ULONG old_size = FIELD_OFFSET(VM_COUNTERS,PrivatePageCount); + HANDLE process; + SIZE_T prev_size; + const SIZE_T alloc_size = 16 * 1024 * 1024; + void *ptr;
status = pNtQueryInformationProcess(NULL, ProcessVmCounters, NULL, sizeof(pvi), NULL); ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, @@ -935,11 +1157,72 @@ static void test_query_process_vm(void) ok( ReturnLength == old_size || ReturnLength == sizeof(pvi), "Inconsistent length %d\n", ReturnLength);
/* Check if we have some return values */ - trace("WorkingSetSize : %ld\n", pvi.WorkingSetSize); - todo_wine - { - ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n"); - } + dump_vm_counters("VM counters for GetCurrentProcess", &pvi); + ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n"); + ok( pvi.PagefileUsage > 0, "Expected a PagefileUsage > 0\n"); + + process = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId()); + status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got %08x\n", status); + CloseHandle(process); + + process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId()); + status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS || broken(!process) /* XP */, "Expected STATUS_SUCCESS, got %08x\n", status); + CloseHandle(process); + + memset(&pvi, 0, sizeof(pvi)); + process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); + status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + + /* Check if we have some return values */ + dump_vm_counters("VM counters for GetCurrentProcessId", &pvi); + ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n"); + ok( pvi.PagefileUsage > 0, "Expected a PagefileUsage > 0\n"); + + CloseHandle(process); + + /* Check if we have real counters */ + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + prev_size = pvi.VirtualSize; + if (winetest_debug > 1) + dump_vm_counters("VM counters before VirtualAlloc", &pvi); + ptr = VirtualAlloc(NULL, alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError()); + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + if (winetest_debug > 1) + dump_vm_counters("VM counters after VirtualAlloc", &pvi); + todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size, + "Expected to be greater than %lu, got %lu\n", prev_size + alloc_size, pvi.VirtualSize); + VirtualFree( ptr, 0, MEM_RELEASE); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + prev_size = pvi.VirtualSize; + if (winetest_debug > 1) + dump_vm_counters("VM counters before VirtualAlloc", &pvi); + ptr = VirtualAlloc(NULL, alloc_size, MEM_RESERVE, PAGE_READWRITE); + ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError()); + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + if (winetest_debug > 1) + dump_vm_counters("VM counters after VirtualAlloc(MEM_RESERVE)", &pvi); + todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size, + "Expected to be greater than %lu, got %lu\n", prev_size + alloc_size, pvi.VirtualSize); + prev_size = pvi.VirtualSize; + + ptr = VirtualAlloc(ptr, alloc_size, MEM_COMMIT, PAGE_READWRITE); + ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError()); + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + if (winetest_debug > 1) + dump_vm_counters("VM counters after VirtualAlloc(MEM_COMMIT)", &pvi); + ok( pvi.VirtualSize == prev_size, + "Expected to equal to %lu, got %lu\n", prev_size, pvi.VirtualSize); + VirtualFree( ptr, 0, MEM_RELEASE); }
static void test_query_process_io(void) @@ -975,7 +1258,7 @@ static void test_query_process_io(void) ok( sizeof(pii) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
/* Check if we have some return values */ - trace("OtherOperationCount : 0x%x%08x\n", (DWORD)(pii.OtherOperationCount >> 32), (DWORD)pii.OtherOperationCount); + trace("OtherOperationCount : 0x%s\n", wine_dbgstr_longlong(pii.OtherOperationCount)); todo_wine { ok( pii.OtherOperationCount > 0, "Expected an OtherOperationCount > 0\n"); @@ -1070,7 +1353,7 @@ static void test_query_process_debug_port(int argc, char **argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugPort, &debug_port, sizeof(debug_port), NULL); - ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status); + ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &debug_port, sizeof(debug_port) - 1, NULL); @@ -1111,6 +1394,40 @@ static void test_query_process_debug_port(int argc, char **argv) ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError()); }
+static void test_query_process_priority(void) +{ + PROCESS_PRIORITY_CLASS priority[2]; + ULONG ReturnLength; + DWORD orig_priority; + NTSTATUS status; + BOOL ret; + + status = pNtQueryInformationProcess(NULL, ProcessPriorityClass, NULL, sizeof(priority[0]), NULL); + ok(status == STATUS_ACCESS_VIOLATION || broken(status == STATUS_INVALID_HANDLE) /* w2k3 */, + "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status); + + status = pNtQueryInformationProcess(NULL, ProcessPriorityClass, &priority, sizeof(priority[0]), NULL); + ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass, &priority, 1, &ReturnLength); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass, &priority, sizeof(priority), &ReturnLength); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + + orig_priority = GetPriorityClass(GetCurrentProcess()); + ret = SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); + ok(ret, "Failed to set priority class: %u\n", GetLastError()); + + status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass, &priority, sizeof(priority[0]), &ReturnLength); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok(priority[0].PriorityClass == PROCESS_PRIOCLASS_BELOW_NORMAL, + "Expected PROCESS_PRIOCLASS_BELOW_NORMAL, got %u\n", priority[0].PriorityClass); + + ret = SetPriorityClass(GetCurrentProcess(), orig_priority); + ok(ret, "Failed to reset priority class: %u\n", GetLastError()); +} + static void test_query_process_handlecount(void) { NTSTATUS status; @@ -1293,27 +1610,27 @@ static void test_query_process_debug_object_handle(int argc, char **argv)
static void test_query_process_debug_flags(int argc, char **argv) { + static const DWORD test_flags[] = { DEBUG_PROCESS, + DEBUG_ONLY_THIS_PROCESS, + DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, + CREATE_SUSPENDED }; DWORD debug_flags = 0xdeadbeef; char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; STARTUPINFOA si = { 0 }; NTSTATUS status; + DEBUG_EVENT ev; + DWORD result; BOOL ret; + int i, j;
- sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee"); - - si.cb = sizeof(si); - ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi); - ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError()); - if (!ret) return; + /* test invalid arguments */ + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, NULL, 0, NULL); + ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* WOW64 */, + "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
- 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) */, + status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, NULL, sizeof(debug_flags), NULL); + ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION || broken(status == STATUS_INVALID_INFO_CLASS) /* WOW64 */, "Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, @@ -1322,45 +1639,123 @@ static void test_query_process_debug_flags(int argc, char **argv)
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); + ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /* WOW64 */, + "Expected STATUS_INVALID_HANDLE, 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); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "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); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
+ /* test ProcessDebugFlags of current process */ 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); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == TRUE, "Expected flag TRUE, got %x.\n", debug_flags);
- for (;;) + for (i = 0; i < sizeof(test_flags)/sizeof(test_flags[0]); i++) { - DEBUG_EVENT ev; + DWORD expected_flags = !(test_flags[i] & DEBUG_ONLY_THIS_PROCESS); + sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee");
- ret = WaitForDebugEvent(&ev, INFINITE); - ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); - if (!ret) break; + si.cb = sizeof(si); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, test_flags[i], NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
- if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; + if (!(test_flags[i] & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))) + { + /* test ProcessDebugFlags before attaching with debugger */ + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == TRUE, "Expected flag TRUE, got %x.\n", debug_flags); + + ret = DebugActiveProcess(pi.dwProcessId); + ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError()); + expected_flags = FALSE; + }
- ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); - ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); - if (!ret) break; - } + /* test ProcessDebugFlags after attaching with debugger */ + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == expected_flags, "Expected flag %x, got %x.\n", expected_flags, debug_flags);
- 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()); + if (!(test_flags[i] & CREATE_SUSPENDED)) + { + /* Continue a couple of times to make sure the process is fully initialized, + * otherwise Windows XP deadlocks in the following DebugActiveProcess(). */ + for (;;) + { + ret = WaitForDebugEvent(&ev, 1000); + ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError()); + if (!ret) break; + + if (ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) break; + + ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); + ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); + if (!ret) break; + } + + result = SuspendThread(pi.hThread); + ok(result == 0, "Expected 0, got %u.\n", result); + } + + ret = DebugActiveProcessStop(pi.dwProcessId); + ok(ret, "DebugActiveProcessStop failed, last error %#x.\n", GetLastError()); + + /* test ProcessDebugFlags after detaching debugger */ + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == expected_flags, "Expected flag %x, got %x.\n", expected_flags, debug_flags); + + ret = DebugActiveProcess(pi.dwProcessId); + ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError()); + + /* test ProcessDebugFlags after re-attaching debugger */ + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == FALSE, "Expected flag FALSE, got %x.\n", debug_flags); + + result = ResumeThread(pi.hThread); + todo_wine ok(result == 2, "Expected 2, got %u.\n", result); + + /* Wait until the process is terminated. On Windows XP the process randomly + * gets stuck in a non-continuable exception, so stop after 100 iterations. + * On Windows 2003, the debugged process disappears (or stops?) without + * any EXIT_PROCESS_DEBUG_EVENT after a couple of events. */ + for (j = 0; j < 100; j++) + { + ret = WaitForDebugEvent(&ev, 1000); + ok(ret || broken(GetLastError() == ERROR_SEM_TIMEOUT), + "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; + } + ok(j < 100 || broken(j >= 100) /* Win XP */, "Expected less than 100 debug events.\n"); + + /* test ProcessDebugFlags after process has terminated */ + status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, + &debug_flags, sizeof(debug_flags), NULL); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == FALSE, "Expected flag FALSE, got %x.\n", debug_flags); + + 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) @@ -1439,7 +1834,7 @@ static void test_mapprotection(void) 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.LowPart = 0x2000; size.u.HighPart = 0; status = pNtCreateSection ( &h, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, @@ -1453,7 +1848,7 @@ static void test_mapprotection(void)
offset.u.LowPart = 0; offset.u.HighPart = 0; - count = 0x1000; + count = 0x2000; 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); @@ -1476,7 +1871,7 @@ static void test_mapprotection(void) ok( retlen == sizeof(info), "Expected STATUS_SUCCESS, got %08x\n", status); ok((info.Protect & ~PAGE_NOCACHE) == PAGE_READWRITE, "addr.Protect is not PAGE_READWRITE, but 0x%x\n", info.Protect);
- status = pNtUnmapViewOfSection (GetCurrentProcess(), addr); + status = pNtUnmapViewOfSection( GetCurrentProcess(), (char *)addr + 0x1050 ); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); pNtClose (h);
@@ -1488,12 +1883,17 @@ static void test_queryvirtualmemory(void) { NTSTATUS status; SIZE_T readcount; + static const WCHAR windowsW[] = {'w','i','n','d','o','w','s'}; static const char teststring[] = "test string"; static char datatestbuf[42] = "abc"; static char rwtestbuf[42]; MEMORY_BASIC_INFORMATION mbi; char stackbuf[42]; HMODULE module; + char buffer_name[sizeof(MEMORY_SECTION_NAME) + MAX_PATH * sizeof(WCHAR)]; + MEMORY_SECTION_NAME *msn = (MEMORY_SECTION_NAME *)buffer_name; + BOOL found; + int i;
module = GetModuleHandleA( "ntdll.dll" ); trace("Check flags of the PE header of NTDLL.DLL at %p\n", module); @@ -1567,6 +1967,43 @@ static void test_queryvirtualmemory(void) "mbi.Protect is 0x%x\n", mbi.Protect); } else skip( "bss is outside of module\n" ); /* this can happen on Mac OS */ + + trace("Check section name of NTDLL.DLL with invalid size\n"); + module = GetModuleHandleA( "ntdll.dll" ); + memset(msn, 0, sizeof(*msn)); + readcount = 0; + status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn, sizeof(*msn), &readcount); + ok( status == STATUS_BUFFER_OVERFLOW, "Expected STATUS_BUFFER_OVERFLOW, got %08x\n", status); + ok( readcount > 0, "Expected readcount to be > 0\n"); + + trace("Check section name of NTDLL.DLL with invalid size\n"); + module = GetModuleHandleA( "ntdll.dll" ); + memset(msn, 0, sizeof(*msn)); + readcount = 0; + status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn, sizeof(*msn) - 1, &readcount); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( readcount > 0, "Expected readcount to be > 0\n"); + + trace("Check section name of NTDLL.DLL\n"); + module = GetModuleHandleA( "ntdll.dll" ); + memset(msn, 0x55, sizeof(*msn)); + memset(buffer_name, 0x77, sizeof(buffer_name)); + readcount = 0; + status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn, sizeof(buffer_name), &readcount); + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok( readcount > 0, "Expected readcount to be > 0\n"); + trace ("Section Name: %s\n", wine_dbgstr_w(msn->SectionFileName.Buffer)); + pRtlDowncaseUnicodeString( &msn->SectionFileName, &msn->SectionFileName, FALSE ); + for (found = FALSE, i = (msn->SectionFileName.Length - sizeof(windowsW)) / sizeof(WCHAR); i >= 0; i--) + found |= !memcmp( &msn->SectionFileName.Buffer[i], windowsW, sizeof(windowsW) ); + ok( found, "Section name does not contain "Windows"\n"); + + trace("Check section name of non mapped memory\n"); + memset(msn, 0, sizeof(*msn)); + readcount = 0; + status = pNtQueryVirtualMemory(NtCurrentProcess(), &buffer_name, MemorySectionName, msn, sizeof(buffer_name), &readcount); + ok( status == STATUS_INVALID_ADDRESS, "Expected STATUS_INVALID_ADDRESS, got %08x\n", status); + ok( readcount == 0 || broken(readcount != 0) /* wow64 */, "Expected readcount to be 0\n"); }
static void test_affinity(void) @@ -1780,6 +2217,39 @@ static void test_thread_start_address(void) CloseHandle(thread); }
+static void test_query_data_alignment(void) +{ + ULONG ReturnLength; + NTSTATUS status; + DWORD value; + + value = 0xdeadbeef; + status = pNtQuerySystemInformation(SystemRecommendedSharedDataAlignment, &value, sizeof(value), &ReturnLength); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); + ok(sizeof(value) == ReturnLength, "Inconsistent length %u\n", ReturnLength); + ok(value == 64, "Expected 64, got %u\n", value); +} + +static void test_working_set_limit(void) +{ + DWORD_PTR lower = 0, upper = ~(DWORD_PTR)0; + MEMORY_BASIC_INFORMATION mbi; + SIZE_T readcount; + NTSTATUS status; + + while (lower != upper) + { + DWORD_PTR check = (lower >> 1) + (upper >> 1) + (lower & upper & 1); + status = pNtQueryVirtualMemory(NtCurrentProcess(), (void *)check, MemoryBasicInformation, + &mbi, sizeof(MEMORY_BASIC_INFORMATION), &readcount); + if (status == STATUS_INVALID_PARAMETER) upper = check; + else lower = check + 1; + } + + trace("working set limit is %p\n", (void *)upper); + ok(upper != ~(DWORD_PTR)0, "expected != ~(DWORD_PTR)0\n"); +} + START_TEST(info) { char **argv; @@ -1825,6 +2295,10 @@ START_TEST(info) trace("Starting test_query_handle()\n"); test_query_handle();
+ /* 0x40 SystemHandleInformation */ + trace("Starting test_query_handle_ex()\n"); + test_query_handle_ex(); + /* 0x15 SystemCacheInformation */ trace("Starting test_query_cache()\n"); test_query_cache(); @@ -1844,6 +2318,7 @@ START_TEST(info) /* 0x49 SystemLogicalProcessorInformation */ trace("Starting test_query_logicalproc()\n"); test_query_logicalproc(); + test_query_logicalprocex();
/* NtPowerInformation */
@@ -1873,6 +2348,10 @@ START_TEST(info) trace("Starting test_process_debug_port()\n"); test_query_process_debug_port(argc, argv);
+ /* 0x12 ProcessPriorityClass */ + trace("Starting test_query_process_priority()\n"); + test_query_process_priority(); + /* 0x14 ProcessHandleCount */ trace("Starting test_query_process_handlecount()\n"); test_query_process_handlecount(); @@ -1911,4 +2390,10 @@ START_TEST(info)
trace("Starting test_thread_start_address()\n"); test_thread_start_address(); + + trace("Starting test_query_data_alignment()\n"); + test_query_data_alignment(); + + trace("Starting test_working_set_limit()\n"); + test_working_set_limit(); } diff --git a/modules/rostests/winetests/ntdll/large_int.c b/modules/rostests/winetests/ntdll/large_int.c index f13ae882d0..4562e6768e 100755 --- a/modules/rostests/winetests/ntdll/large_int.c +++ b/modules/rostests/winetests/ntdll/large_int.c @@ -33,6 +33,8 @@ static VOID (WINAPI *pRtlFreeAnsiString)(PSTRING); static NTSTATUS (WINAPI *pRtlInt64ToUnicodeString)(ULONGLONG, ULONG, UNICODE_STRING *); static NTSTATUS (WINAPI *pRtlLargeIntegerToChar)(ULONGLONG *, ULONG, ULONG, PCHAR); static NTSTATUS (WINAPI *pRtlUnicodeStringToAnsiString)(STRING *, const UNICODE_STRING *, BOOLEAN); +static void (WINAPI *p_alldvrm)(LONGLONG, LONGLONG); +static void (WINAPI *p_aulldvrm)(ULONGLONG, ULONGLONG);
static void InitFunctionPtrs(void) @@ -45,6 +47,8 @@ static void InitFunctionPtrs(void) pRtlInt64ToUnicodeString = (void *)GetProcAddress(hntdll, "RtlInt64ToUnicodeString"); pRtlLargeIntegerToChar = (void *)GetProcAddress(hntdll, "RtlLargeIntegerToChar"); pRtlUnicodeStringToAnsiString = (void *)GetProcAddress(hntdll, "RtlUnicodeStringToAnsiString"); + p_alldvrm = (void *)GetProcAddress(hntdll, "_alldvrm"); + p_aulldvrm = (void *)GetProcAddress(hntdll, "_aulldvrm"); } /* if */ }
@@ -113,10 +117,9 @@ static void test_RtlExtendedMagicDivide(void) for (i = 0; i < NB_MAGIC_DIVIDE; i++) { result = pRtlExtendedMagicDivide(magic_divide[i].a, magic_divide[i].b, magic_divide[i].shift); ok(result == magic_divide[i].result, - "call failed: RtlExtendedMagicDivide(0x%x%08x, 0x%x%08x, %d) has result 0x%x%08x, expected 0x%x%08x\n", - (DWORD)(magic_divide[i].a >> 32), (DWORD)magic_divide[i].a, (DWORD)(magic_divide[i].b >> 32), - (DWORD)magic_divide[i].b, magic_divide[i].shift, (DWORD)(result >> 32), (DWORD)result, - (DWORD)(magic_divide[i].result >> 32), (DWORD)magic_divide[i].result); + "call failed: RtlExtendedMagicDivide(0x%s, 0x%s, %d) has result 0x%s, expected 0x%s\n", + wine_dbgstr_longlong(magic_divide[i].a), wine_dbgstr_longlong(magic_divide[i].b), magic_divide[i].shift, + wine_dbgstr_longlong(result), wine_dbgstr_longlong(magic_divide[i].result)); } }
@@ -332,14 +335,12 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t } /* if */ } else { ok(result == largeint2str->result, - "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) has result %x, expected: %x\n", - test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, - largeint2str->base, result, largeint2str->result); + "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) has result %x, expected: %x\n", + test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, result, largeint2str->result); if (result == STATUS_SUCCESS) { ok(unicode_string.Buffer[unicode_string.Length/sizeof(WCHAR)] == '\0', - "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string "%s" is not NULL terminated\n", - test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, - largeint2str->base, ansi_str.Buffer); + "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string "%s" is not NULL terminated\n", + test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, ansi_str.Buffer); } /* if */ } /* if */ ok(memcmp(unicode_string.Buffer, expected_unicode_string.Buffer, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0, @@ -347,12 +348,12 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t test_num, (DWORD)(largeint2str->value >>32), (DWORD)largeint2str->value, largeint2str->base, ansi_str.Buffer, expected_ansi_str.Buffer); ok(unicode_string.Length == expected_unicode_string.Length, - "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has Length %d, expected: %d\n", - test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string has Length %d, expected: %d\n", + test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, unicode_string.Length, expected_unicode_string.Length); ok(unicode_string.MaximumLength == expected_unicode_string.MaximumLength, - "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has MaximumLength %d, expected: %d\n", - test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string has MaximumLength %d, expected: %d\n", + test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, unicode_string.MaximumLength, expected_unicode_string.MaximumLength); pRtlFreeAnsiString(&expected_ansi_str); pRtlFreeAnsiString(&ansi_str); @@ -392,12 +393,12 @@ static void one_RtlLargeIntegerToChar_test(int test_num, const largeint2str_t *l result = pRtlLargeIntegerToChar(&value, largeint2str->base, largeint2str->MaximumLength, dest_str); } /* if */ ok(result == largeint2str->result, - "(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) has result %x, expected: %x\n", - test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + "(test %d): RtlLargeIntegerToChar(0x%s, %d, %d, [out]) has result %x, expected: %x\n", + test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, largeint2str->MaximumLength, result, largeint2str->result); ok(memcmp(dest_str, largeint2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0, - "(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) assigns string "%s", expected: "%s"\n", - test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base, + "(test %d): RtlLargeIntegerToChar(0x%s, %d, %d, [out]) assigns string "%s", expected: "%s"\n", + test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, largeint2str->MaximumLength, dest_str, largeint2str->Buffer); }
@@ -415,30 +416,89 @@ static void test_RtlLargeIntegerToChar(void) value = largeint2str[0].value; result = pRtlLargeIntegerToChar(&value, 20, largeint2str[0].MaximumLength, NULL); ok(result == STATUS_INVALID_PARAMETER, - "(test a): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", - (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20, + "(test a): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n", + wine_dbgstr_longlong(largeint2str[0].value), 20, largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER);
result = pRtlLargeIntegerToChar(&value, 20, 0, NULL); ok(result == STATUS_INVALID_PARAMETER, - "(test b): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", - (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20, + "(test b): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n", + wine_dbgstr_longlong(largeint2str[0].value), 20, largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER);
result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, 0, NULL); ok(result == STATUS_BUFFER_OVERFLOW, - "(test c): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", - (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, - largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW); + "(test c): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n", + wine_dbgstr_longlong(largeint2str[0].value), largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW);
result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, largeint2str[0].MaximumLength, NULL); ok(result == STATUS_ACCESS_VIOLATION, - "(test d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n", - (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, + "(test d): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n", + wine_dbgstr_longlong(largeint2str[0].value), largeint2str[0].base, largeint2str[0].MaximumLength, result, STATUS_ACCESS_VIOLATION); }
+#ifdef __i386__ + +#include "pshpack1.h" +struct lldvrm_thunk +{ + BYTE push_ebx; /* pushl %ebx */ + DWORD push_esp1; /* pushl 24(%esp) */ + DWORD push_esp2; /* pushl 24(%esp) */ + DWORD push_esp3; /* pushl 24(%esp) */ + DWORD push_esp4; /* pushl 24(%esp) */ + DWORD call; /* call 24(%esp) */ + WORD mov_ecx_eax; /* movl %ecx,%eax */ + WORD mov_ebx_edx; /* movl %ebx,%edx */ + BYTE pop_ebx; /* popl %ebx */ + BYTE ret; /* ret */ +}; +#include "poppack.h" + +static void test__alldvrm(void) +{ + struct lldvrm_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ULONGLONG (CDECL *call_lldvrm_func)(void *func, ULONGLONG, ULONGLONG) = (void *)thunk; + ULONGLONG ret; + + memset(thunk, 0x90, sizeof(*thunk)); + thunk->push_ebx = 0x53; /* pushl %ebx */ + thunk->push_esp1 = 0x182474ff; /* pushl 24(%esp) */ + thunk->push_esp2 = 0x182474ff; /* pushl 24(%esp) */ + thunk->push_esp3 = 0x182474ff; /* pushl 24(%esp) */ + thunk->push_esp4 = 0x182474ff; /* pushl 24(%esp) */ + thunk->call = 0x182454ff; /* call 24(%esp) */ + thunk->pop_ebx = 0x5b; /* popl %ebx */ + thunk->ret = 0xc3; /* ret */ + + ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, 3); + ok(ret == 0x61172255b66c77ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, -3); + ok(ret == 0xff9ee8ddaa499389ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + + ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, 3); + ok(ret == 0x61172255b66c77ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, -3); + ok(ret == 0, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + + thunk->mov_ecx_eax = 0xc889; + thunk->mov_ebx_edx = 0xda89; + + ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, 3); + ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, -3); + ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + + ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, 3); + ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); + ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, -3); + ok(ret == 0x123456701234567ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret); +} +#endif /* __i386__ */ + + START_TEST(large_int) { InitFunctionPtrs(); @@ -449,4 +509,8 @@ START_TEST(large_int) test_RtlInt64ToUnicodeString(); if (pRtlLargeIntegerToChar) test_RtlLargeIntegerToChar(); + +#ifdef __i386__ + test__alldvrm(); +#endif /* __i386__ */ } diff --git a/modules/rostests/winetests/ntdll/ntdll_test.h b/modules/rostests/winetests/ntdll/ntdll_test.h index 8d88308315..84ed6a4a71 100755 --- a/modules/rostests/winetests/ntdll/ntdll_test.h +++ b/modules/rostests/winetests/ntdll/ntdll_test.h @@ -20,10 +20,6 @@
#include <stdarg.h>
-#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x500 /* For NTSTATUS */ -#endif - #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" diff --git a/modules/rostests/winetests/ntdll/om.c b/modules/rostests/winetests/ntdll/om.c index 65e9260a1e..651db0a1ee 100644 --- a/modules/rostests/winetests/ntdll/om.c +++ b/modules/rostests/winetests/ntdll/om.c @@ -33,12 +33,25 @@ static NTSTATUS (WINAPI *pNtCreateEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_A static NTSTATUS (WINAPI *pNtOpenEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtPulseEvent) ( HANDLE, PULONG ); static NTSTATUS (WINAPI *pNtQueryEvent) ( HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG ); +static NTSTATUS (WINAPI *pNtCreateJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); +static NTSTATUS (WINAPI *pNtOpenJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); +static NTSTATUS (WINAPI *pNtCreateKey)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG, + const UNICODE_STRING *, ULONG, PULONG ); +static NTSTATUS (WINAPI *pNtOpenKey)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); +static NTSTATUS (WINAPI *pNtDeleteKey)( HANDLE ); +static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, + ULONG, ULONG, ULONG, PLARGE_INTEGER ); static NTSTATUS (WINAPI *pNtCreateMutant)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN ); static NTSTATUS (WINAPI *pNtOpenMutant) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES ); +static NTSTATUS (WINAPI *pNtQueryMutant) ( HANDLE, MUTANT_INFORMATION_CLASS, PVOID, ULONG, PULONG ); +static NTSTATUS (WINAPI *pNtReleaseMutant)( HANDLE, PLONG ); static NTSTATUS (WINAPI *pNtCreateSemaphore)( PHANDLE, ACCESS_MASK,const POBJECT_ATTRIBUTES,LONG,LONG ); +static NTSTATUS (WINAPI *pNtOpenSemaphore)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtCreateTimer) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, TIMER_TYPE ); +static NTSTATUS (WINAPI *pNtOpenTimer)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtCreateSection)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, const PLARGE_INTEGER, ULONG, ULONG, HANDLE ); +static NTSTATUS (WINAPI *pNtOpenSection)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG ); static NTSTATUS (WINAPI *pNtClose) ( HANDLE ); static NTSTATUS (WINAPI *pNtCreateNamedPipeFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, @@ -55,11 +68,28 @@ static NTSTATUS (WINAPI *pNtOpenKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJECT static NTSTATUS (WINAPI *pNtWaitForKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); +static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); +static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
#define KEYEDEVENT_WAIT 0x0001 #define KEYEDEVENT_WAKE 0x0002 #define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003)
+#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) + +static LPCSTR wine_dbgstr_us( const UNICODE_STRING *us ) +{ + if (!us) return "(null)"; + return wine_dbgstr_wn(us->Buffer, us->Length / sizeof(WCHAR)); +} + +static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n ) +{ + if (n <= 0) return 0; + while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + static void test_case_sensitive (void) { static const WCHAR buffer1[] = {'\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\','t','e','s','t',0}; @@ -165,33 +195,34 @@ static void test_namespace_pipe(void) status == STATUS_OBJECT_NAME_INVALID, /* vista */ "NtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND got(%08x)\n", status);
+ str.Length -= 4 * sizeof(WCHAR); + status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0); + ok(status == STATUS_SUCCESS, "NtOpenFile should have succeeded got %08x\n", status); + pNtClose( h ); + + str.Length -= sizeof(WCHAR); + status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0); + ok(status == STATUS_SUCCESS, "NtOpenFile should have succeeded got %08x\n", status); + pNtClose( h ); + pNtClose(pipe); }
#define DIRECTORY_QUERY (0x0001) #define SYMBOLIC_LINK_QUERY 0x0001
-#define DIR_TEST_CREATE_FAILURE(h,e) \ - status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr);\ - ok(status == e,"NtCreateDirectoryObject should have failed with %s got(%08x)\n", #e, status); -#define DIR_TEST_OPEN_FAILURE(h,e) \ - status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr);\ - ok(status == e,"NtOpenDirectoryObject should have failed with %s got(%08x)\n", #e, status); -#define DIR_TEST_CREATE_OPEN_FAILURE(h,n,e) \ - pRtlCreateUnicodeStringFromAsciiz(&str, n);\ - DIR_TEST_CREATE_FAILURE(h,e) DIR_TEST_OPEN_FAILURE(h,e)\ - pRtlFreeUnicodeString(&str); - -#define DIR_TEST_CREATE_SUCCESS(h) \ - status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr); \ - ok(status == STATUS_SUCCESS, "Failed to create Directory(%08x)\n", status); -#define DIR_TEST_OPEN_SUCCESS(h) \ - status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr); \ - ok(status == STATUS_SUCCESS, "Failed to open Directory(%08x)\n", status); -#define DIR_TEST_CREATE_OPEN_SUCCESS(h,n) \ - pRtlCreateUnicodeStringFromAsciiz(&str, n);\ - DIR_TEST_CREATE_SUCCESS(&h) pNtClose(h); DIR_TEST_OPEN_SUCCESS(&h) pNtClose(h); \ - pRtlFreeUnicodeString(&str); +#define DIR_TEST_CREATE_OPEN(n,e) \ + do { \ + HANDLE h; \ + pRtlCreateUnicodeStringFromAsciiz(&str, n); \ + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); \ + ok( status == e, "NtCreateDirectoryObject(%s) got %08x\n", n, status ); \ + if (!status) pNtClose( h ); \ + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); \ + ok( status == e, "NtOpenDirectoryObject(%s) got %08x\n", n, status ); \ + if (!status) pNtClose( h ); \ + pRtlFreeUnicodeString(&str); \ + } while(0)
static BOOL is_correct_dir( HANDLE dir, const char *name ) { @@ -216,13 +247,14 @@ static HANDLE get_base_dir(void) UNICODE_STRING str; OBJECT_ATTRIBUTES attr; HANDLE dir, h; - unsigned int i; + char name[40];
h = CreateMutexA(NULL, FALSE, objname); ok(h != 0, "CreateMutexA failed got ret=%p (%d)\n", h, GetLastError()); InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL);
- pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects\Local"); + sprintf( name, "\BaseNamedObjects\Session\%u", NtCurrentTeb()->Peb->SessionId ); + pRtlCreateUnicodeStringFromAsciiz(&str, name ); status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr); pRtlFreeUnicodeString(&str); if (!status && is_correct_dir( dir, objname )) goto done; @@ -234,16 +266,6 @@ static HANDLE get_base_dir(void) if (!status && is_correct_dir( dir, objname )) goto done; if (!status) pNtClose( dir );
- for (i = 0; i < 20; i++) - { - char name[40]; - sprintf( name, "\BaseNamedObjects\Session\%u", i ); - pRtlCreateUnicodeStringFromAsciiz(&str, name ); - status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr); - pRtlFreeUnicodeString(&str); - if (!status && is_correct_dir( dir, objname )) goto done; - if (!status) pNtClose( dir ); - } dir = 0;
done: @@ -262,10 +284,12 @@ static void test_name_collisions(void)
InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\"); - DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_COLLISION) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateDirectoryObject got %08x\n", status ); InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL);
- DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_EXISTS) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_EXISTS, "NtCreateDirectoryObject got %08x\n", status ); pNtClose(h); status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE); ok(status == STATUS_OBJECT_TYPE_MISMATCH, @@ -356,12 +380,529 @@ static void test_name_collisions(void) pNtClose(dir); }
+static void test_all_kernel_objects( UINT line, OBJECT_ATTRIBUTES *attr, + NTSTATUS create_expect, NTSTATUS open_expect ) +{ + UNICODE_STRING target; + LARGE_INTEGER size; + NTSTATUS status, status2; + HANDLE ret, ret2; + + pRtlCreateUnicodeStringFromAsciiz( &target, "\DosDevices" ); + size.QuadPart = 4096; + + status = pNtCreateMutant( &ret, GENERIC_ALL, attr, FALSE ); + ok( status == create_expect, "%u: NtCreateMutant failed %x\n", line, status ); + status2 = pNtOpenMutant( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenMutant failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateSemaphore( &ret, GENERIC_ALL, attr, 1, 2 ); + ok( status == create_expect, "%u: NtCreateSemaphore failed %x\n", line, status ); + status2 = pNtOpenSemaphore( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenSemaphore failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateEvent( &ret, GENERIC_ALL, attr, 1, 0 ); + ok( status == create_expect, "%u: NtCreateEvent failed %x\n", line, status ); + status2 = pNtOpenEvent( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenEvent failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, attr, 0 ); + ok( status == create_expect, "%u: NtCreateKeyedEvent failed %x\n", line, status ); + status2 = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenKeyedEvent failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateTimer( &ret, GENERIC_ALL, attr, NotificationTimer ); + ok( status == create_expect, "%u: NtCreateTimer failed %x\n", line, status ); + status2 = pNtOpenTimer( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenTimer failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateIoCompletion( &ret, GENERIC_ALL, attr, 0 ); + ok( status == create_expect, "%u: NtCreateCompletion failed %x\n", line, status ); + status2 = pNtOpenIoCompletion( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenCompletion failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateJobObject( &ret, GENERIC_ALL, attr ); + ok( status == create_expect, "%u: NtCreateJobObject failed %x\n", line, status ); + status2 = pNtOpenJobObject( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenJobObject failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, attr ); + ok( status == create_expect, "%u: NtCreateDirectoryObject failed %x\n", line, status ); + status2 = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenDirectoryObject failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, attr, &target ); + ok( status == create_expect, "%u: NtCreateSymbolicLinkObject failed %x\n", line, status ); + status2 = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, attr ); + ok( status2 == open_expect, "%u: NtOpenSymbolicLinkObject failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + status = pNtCreateSection( &ret, SECTION_MAP_WRITE, attr, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == create_expect, "%u: NtCreateSection failed %x\n", line, status ); + status2 = pNtOpenSection( &ret2, SECTION_MAP_WRITE, attr ); + ok( status2 == open_expect, "%u: NtOpenSection failed %x\n", line, status2 ); + if (!status) pNtClose( ret ); + if (!status2) pNtClose( ret2 ); + pRtlFreeUnicodeString( &target ); +} + +static void test_name_limits(void) +{ + static const WCHAR localW[] = {'\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\','L','o','c','a','l',0}; + static const WCHAR pipeW[] = {'\','D','e','v','i','c','e','\','N','a','m','e','d','P','i','p','e','\'}; + static const WCHAR mailslotW[] = {'\','D','e','v','i','c','e','\','M','a','i','l','S','l','o','t','\'}; + static const WCHAR registryW[] = {'\','R','E','G','I','S','T','R','Y','\','M','a','c','h','i','n','e','\','S','O','F','T','W','A','R','E','\','M','i','c','r','o','s','o','f','t','\'}; + OBJECT_ATTRIBUTES attr, attr2, attr3; + IO_STATUS_BLOCK iosb; + LARGE_INTEGER size, timeout; + UNICODE_STRING str, str2, target; + NTSTATUS status; + HANDLE ret, ret2; + DWORD i; + + InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); + InitializeObjectAttributes( &attr2, &str, 0, (HANDLE)0xdeadbeef, NULL ); + InitializeObjectAttributes( &attr3, &str, 0, 0, NULL ); + str.Buffer = HeapAlloc( GetProcessHeap(), 0, 65536 + sizeof(registryW)); + str.MaximumLength = 65534; + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i] = 'a'; + size.QuadPart = 4096; + pRtlCreateUnicodeStringFromAsciiz( &target, "\DosDevices" ); + + if (!(attr.RootDirectory = get_base_dir())) + { + win_skip( "couldn't find the BaseNamedObjects dir\n" ); + return; + } + + str.Length = 0; + status = pNtCreateMutant( &ret, GENERIC_ALL, &attr2, FALSE ); + ok( status == STATUS_SUCCESS, "%u: NtCreateMutant failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenMutant( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenMutant failed %x\n", str.Length, status ); + status = pNtOpenMutant( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenMutant failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr2, 1, 2 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateSemaphore failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenSemaphore( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSemaphore failed %x\n", str.Length, status ); + status = pNtOpenSemaphore( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenSemaphore failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateEvent( &ret, GENERIC_ALL, &attr2, 1, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateEvent failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenEvent( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenEvent failed %x\n", str.Length, status ); + status = pNtOpenEvent( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenEvent failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr2, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateKeyedEvent failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenKeyedEvent failed %x\n", str.Length, status ); + status = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenKeyedEvent failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateTimer( &ret, GENERIC_ALL, &attr2, NotificationTimer ); + ok( status == STATUS_SUCCESS, "%u: NtCreateTimer failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenTimer( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenTimer failed %x\n", str.Length, status ); + status = pNtOpenTimer( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenTimer failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr2, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateCompletion failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenIoCompletion( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenCompletion failed %x\n", str.Length, status ); + status = pNtOpenIoCompletion( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenCompletion failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr2 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateJobObject failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenJobObject( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenJobObject failed %x\n", str.Length, status ); + status = pNtOpenJobObject( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenJobObject failed %x\n", str.Length, status ); + pNtClose( ret ); + status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr2 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateDirectoryObject failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED), /* winxp */ + "%u: NtOpenDirectoryObject failed %x\n", str.Length, status ); + if (!status) pNtClose( ret2 ); + status = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_SUCCESS, "%u: NtOpenDirectoryObject failed %x\n", str.Length, status ); + pNtClose( ret2 ); + pNtClose( ret ); + status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr2, &target ); + ok( status == STATUS_SUCCESS, "%u: NtCreateSymbolicLinkObject failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSymbolicLinkObject failed %x\n", str.Length, status ); + status = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, &attr3 ); + ok( status == STATUS_SUCCESS, "%u: NtOpenSymbolicLinkObject failed %x\n", str.Length, status ); + pNtClose( ret2 ); + pNtClose( ret ); + status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr2, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == STATUS_SUCCESS, "%u: NtCreateSection failed %x\n", str.Length, status ); + attr3.RootDirectory = ret; + status = pNtOpenSection( &ret2, SECTION_MAP_WRITE, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSection failed %x\n", str.Length, status ); + status = pNtOpenSection( &ret2, SECTION_MAP_WRITE, &attr3 ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, + "%u: NtOpenSection failed %x\n", str.Length, status ); + pNtClose( ret ); + + str.Length = 67; + test_all_kernel_objects( __LINE__, &attr2, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_INVALID ); + + str.Length = 65532; + test_all_kernel_objects( __LINE__, &attr, STATUS_SUCCESS, STATUS_SUCCESS ); + + str.Length = 65534; + test_all_kernel_objects( __LINE__, &attr, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_INVALID ); + + str.Length = 128; + for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++) + { + if (attr.Length == sizeof(attr)) + test_all_kernel_objects( __LINE__, &attr, STATUS_SUCCESS, STATUS_SUCCESS ); + else + test_all_kernel_objects( __LINE__, &attr, STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER ); + } + attr.Length = sizeof(attr); + + /* null attributes or ObjectName, with or without RootDirectory */ + attr3.RootDirectory = 0; + attr2.ObjectName = attr3.ObjectName = NULL; + test_all_kernel_objects( __LINE__, &attr2, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_INVALID ); + test_all_kernel_objects( __LINE__, &attr3, STATUS_SUCCESS, STATUS_OBJECT_PATH_SYNTAX_BAD ); + + attr3.ObjectName = &str2; + pRtlInitUnicodeString( &str2, localW ); + status = pNtOpenSymbolicLinkObject( &ret, SYMBOLIC_LINK_QUERY, &attr3 ); + ok( status == STATUS_SUCCESS, "can't open BaseNamedObjects\Local %x\n", status ); + attr3.ObjectName = &str; + attr3.RootDirectory = ret; + test_all_kernel_objects( __LINE__, &attr3, STATUS_OBJECT_TYPE_MISMATCH, STATUS_OBJECT_TYPE_MISMATCH ); + pNtClose( attr3.RootDirectory ); + + status = pNtCreateMutant( &ret, GENERIC_ALL, NULL, FALSE ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateMutant failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenMutant( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenMutant failed %x\n", status ); + status = pNtCreateSemaphore( &ret, GENERIC_ALL, NULL, 1, 2 ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateSemaphore failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenSemaphore( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenSemaphore failed %x\n", status ); + status = pNtCreateEvent( &ret, GENERIC_ALL, NULL, 1, 0 ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateEvent failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenEvent( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenEvent failed %x\n", status ); + status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, NULL, 0 ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateKeyedEvent failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenKeyedEvent( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenKeyedEvent failed %x\n", status ); + status = pNtCreateTimer( &ret, GENERIC_ALL, NULL, NotificationTimer ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateTimer failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenTimer( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenTimer failed %x\n", status ); + status = pNtCreateIoCompletion( &ret, GENERIC_ALL, NULL, 0 ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateCompletion failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenIoCompletion( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenCompletion failed %x\n", status ); + status = pNtCreateJobObject( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateJobObject failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenJobObject( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenJobObject failed %x\n", status ); + status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateDirectoryObject failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenDirectoryObject( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenDirectoryObject failed %x\n", status ); + status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, NULL, &target ); + ok( status == STATUS_ACCESS_VIOLATION || broken( status == STATUS_SUCCESS), /* winxp */ + "NULL: NtCreateSymbolicLinkObject failed %x\n", status ); + if (!status) pNtClose( ret ); + status = pNtOpenSymbolicLinkObject( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenSymbolicLinkObject failed %x\n", status ); + status = pNtCreateSection( &ret, SECTION_MAP_WRITE, NULL, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == STATUS_SUCCESS, "NULL: NtCreateSection failed %x\n", status ); + pNtClose( ret ); + status = pNtOpenSection( &ret, SECTION_MAP_WRITE, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenSection failed %x\n", status ); + attr2.ObjectName = attr3.ObjectName = &str; + + /* named pipes */ + memcpy( str.Buffer, pipeW, sizeof(pipeW) ); + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(pipeW)/sizeof(WCHAR)] = 'a'; + str.Length = 0; + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + timeout.QuadPart = -10000; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + str.Length = 67; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + str.Length = 128; + for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++) + { + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + if (attr.Length == sizeof(attr)) + { + ok( status == STATUS_SUCCESS, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + pNtClose( ret ); + } + else ok( status == STATUS_INVALID_PARAMETER, + "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + } + attr.Length = sizeof(attr); + str.Length = 65532; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_SUCCESS, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + pNtClose( ret ); + str.Length = 65534; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status ); + attr3.RootDirectory = 0; + attr2.ObjectName = attr3.ObjectName = NULL; + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NULL: NtCreateNamedPipeFile failed %x\n", status ); + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr3, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NULL: NtCreateNamedPipeFile failed %x\n", status ); + status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, NULL, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtCreateNamedPipeFile failed %x\n", status ); + attr2.ObjectName = attr3.ObjectName = &str; + + /* mailslots */ + memcpy( str.Buffer, mailslotW, sizeof(mailslotW) ); + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(mailslotW)/sizeof(WCHAR)] = 'a'; + str.Length = 0; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + str.Length = 67; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + str.Length = 128; + for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++) + { + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + if (attr.Length == sizeof(attr)) + { + ok( status == STATUS_SUCCESS, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + pNtClose( ret ); + } + else ok( status == STATUS_INVALID_PARAMETER, + "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + } + attr.Length = sizeof(attr); + str.Length = 65532; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_SUCCESS, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + pNtClose( ret ); + str.Length = 65534; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMailslotFile failed %x\n", str.Length, status ); + attr3.RootDirectory = 0; + attr2.ObjectName = attr3.ObjectName = NULL; + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NULL: NtCreateMailslotFile failed %x\n", status ); + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr3, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NULL: NtCreateMailslotFile failed %x\n", status ); + status = pNtCreateMailslotFile( &ret, GENERIC_ALL, NULL, &iosb, 0, 0, 0, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "NULL: NtCreateMailslotFile failed %x\n", status ); + attr2.ObjectName = attr3.ObjectName = &str; + + /* registry keys */ + memcpy( str.Buffer, registryW, sizeof(registryW) ); + for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(registryW)/sizeof(WCHAR)] = 'a'; + str.Length = 0; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + todo_wine + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtCreateKey( &ret, GENERIC_ALL, &attr2, 0, NULL, 0, NULL ); + ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr2 ); + ok( status == STATUS_INVALID_HANDLE, "%u: NtOpenKey failed %x\n", str.Length, status ); + str.Length = sizeof(registryW) + 250 * sizeof(WCHAR) + 1; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_INVALID_PARAMETER || + broken( status == STATUS_SUCCESS ), /* wow64 */ + "%u: NtCreateKey failed %x\n", str.Length, status ); + if (!status) + { + pNtDeleteKey( ret ); + pNtClose( ret ); + } + str.Length = sizeof(registryW) + 256 * sizeof(WCHAR); + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, + "%u: NtCreateKey failed %x\n", str.Length, status ); + if (!status) + { + status = pNtOpenKey( &ret2, KEY_READ, &attr ); + ok( status == STATUS_SUCCESS, "%u: NtOpenKey failed %x\n", str.Length, status ); + pNtClose( ret2 ); + attr3.RootDirectory = ret; + str.Length = 0; + status = pNtOpenKey( &ret2, KEY_READ, &attr3 ); + ok( status == STATUS_SUCCESS, "%u: NtOpenKey failed %x\n", str.Length, status ); + pNtClose( ret2 ); + pNtDeleteKey( ret ); + pNtClose( ret ); + + str.Length = sizeof(registryW) + 256 * sizeof(WCHAR); + for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++) + { + if (attr.Length == sizeof(attr)) + { + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_SUCCESS, "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret2, KEY_READ, &attr ); + ok( status == STATUS_SUCCESS, "%u: NtOpenKey failed %x\n", str.Length, status ); + pNtClose( ret2 ); + pNtDeleteKey( ret ); + pNtClose( ret ); + } + else + { + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret2, KEY_READ, &attr ); + ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %x\n", str.Length, status ); + } + } + attr.Length = sizeof(attr); + } + str.Length = sizeof(registryW) + 256 * sizeof(WCHAR) + 1; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_INVALID_PARAMETER || + broken( status == STATUS_SUCCESS ), /* win7 */ + "%u: NtCreateKey failed %x\n", str.Length, status ); + if (!status) + { + pNtDeleteKey( ret ); + pNtClose( ret ); + } + status = pNtOpenKey( &ret, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_INVALID_PARAMETER || + broken( status == STATUS_OBJECT_NAME_NOT_FOUND ), /* wow64 */ + "%u: NtOpenKey failed %x\n", str.Length, status ); + str.Length++; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %x\n", str.Length, status ); + str.Length = 2000; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %x\n", str.Length, status ); + /* some Windows versions change the error past 2050 chars, others past 4066 chars, some don't */ + str.Length = 5000; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_BUFFER_OVERFLOW || + status == STATUS_BUFFER_TOO_SMALL || + status == STATUS_INVALID_PARAMETER, + "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr ); + todo_wine + ok( status == STATUS_BUFFER_OVERFLOW || + status == STATUS_BUFFER_TOO_SMALL || + status == STATUS_INVALID_PARAMETER, + "%u: NtOpenKey failed %x\n", str.Length, status ); + str.Length = 65534; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL ); + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_BUFFER_OVERFLOW || + status == STATUS_BUFFER_TOO_SMALL, + "%u: NtCreateKey failed %x\n", str.Length, status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr ); + todo_wine + ok( status == STATUS_OBJECT_NAME_INVALID || + status == STATUS_BUFFER_OVERFLOW || + status == STATUS_BUFFER_TOO_SMALL, + "%u: NtOpenKey failed %x\n", str.Length, status ); + attr3.RootDirectory = 0; + attr2.ObjectName = attr3.ObjectName = NULL; + status = pNtCreateKey( &ret, GENERIC_ALL, &attr2, 0, NULL, 0, NULL ); + todo_wine + ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, + "NULL: NtCreateKey failed %x\n", status ); + status = pNtCreateKey( &ret, GENERIC_ALL, &attr3, 0, NULL, 0, NULL ); + todo_wine + ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtCreateKey failed %x\n", status ); + status = pNtCreateKey( &ret, GENERIC_ALL, NULL, 0, NULL, 0, NULL ); + ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtCreateKey failed %x\n", status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr2 ); + ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, + "NULL: NtOpenKey failed %x\n", status ); + status = pNtOpenKey( &ret, GENERIC_ALL, &attr3 ); + ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtOpenKey failed %x\n", status ); + status = pNtOpenKey( &ret, GENERIC_ALL, NULL ); + ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtOpenKey failed %x\n", status ); + attr2.ObjectName = attr3.ObjectName = &str; + + pRtlFreeUnicodeString( &str ); + pRtlFreeUnicodeString( &target ); +} + static void test_directory(void) { NTSTATUS status; UNICODE_STRING str; OBJECT_ATTRIBUTES attr; - HANDLE dir, dir1, h; + HANDLE dir, dir1, h, h2; BOOL is_nt4;
/* No name and/or no attributes */ @@ -380,28 +921,34 @@ static void test_directory(void) "NtOpenDirectoryObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status);
InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); - DIR_TEST_CREATE_SUCCESS(&dir) - DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) + status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenDirectoryObject got %08x\n", status );
/* Bad name */ InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, ""); - DIR_TEST_CREATE_SUCCESS(&h) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pNtClose(h); - DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenDirectoryObject got %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(dir);
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", STATUS_OBJECT_PATH_SYNTAX_BAD) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\BaseNamedObjects\", STATUS_OBJECT_NAME_INVALID) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects", STATUS_OBJECT_NAME_INVALID) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\BaseNamedObjects\\om.c-test", STATUS_OBJECT_NAME_INVALID) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\BaseNamedObjects\om.c-test\", STATUS_OBJECT_PATH_NOT_FOUND) + DIR_TEST_CREATE_OPEN( "BaseNamedObjects", STATUS_OBJECT_PATH_SYNTAX_BAD ); + DIR_TEST_CREATE_OPEN( "\BaseNamedObjects\", STATUS_OBJECT_NAME_INVALID ); + DIR_TEST_CREATE_OPEN( "\\BaseNamedObjects", STATUS_OBJECT_NAME_INVALID ); + DIR_TEST_CREATE_OPEN( "\BaseNamedObjects\\om.c-test", STATUS_OBJECT_NAME_INVALID ); + DIR_TEST_CREATE_OPEN( "\BaseNamedObjects\om.c-test\", STATUS_OBJECT_PATH_NOT_FOUND );
pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects\om.c-test"); - DIR_TEST_CREATE_SUCCESS(&h) - DIR_TEST_OPEN_SUCCESS(&dir1) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); + status = pNtOpenDirectoryObject( &dir1, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(h); pNtClose(dir1); @@ -423,9 +970,43 @@ static void test_directory(void) pRtlFreeUnicodeString(&str); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "one more level"); - DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_TYPE_MISMATCH) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateDirectoryObject got %08x\n", status ); pRtlFreeUnicodeString(&str);
+ pRtlCreateUnicodeStringFromAsciiz( &str, "\BaseNamedObjects\Local\om.c-test" ); + InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); + status = pNtCreateDirectoryObject( &dir1, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); + pRtlFreeUnicodeString( &str ); + pRtlCreateUnicodeStringFromAsciiz( &str, "om.c-test" ); + InitializeObjectAttributes( &attr, &str, 0, dir, NULL ); + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "Failed to open directory %08x\n", status ); + if (!status) pNtClose(h); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "om.c-event" ); + InitializeObjectAttributes( &attr, &str, 0, dir1, NULL ); + status = pNtCreateEvent( &h, GENERIC_ALL, &attr, 1, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateEvent failed %x\n", status ); + status = pNtOpenEvent( &h2, GENERIC_ALL, &attr ); + ok( status == STATUS_SUCCESS, "NtOpenEvent failed %x\n", status ); + pNtClose( h2 ); + pRtlFreeUnicodeString( &str ); + pRtlCreateUnicodeStringFromAsciiz( &str, "om.c-test\om.c-event" ); + InitializeObjectAttributes( &attr, &str, 0, dir, NULL ); + status = pNtOpenEvent( &h2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenEvent failed %x\n", status ); + pRtlFreeUnicodeString( &str ); + pRtlCreateUnicodeStringFromAsciiz( &str, "\BasedNamedObjects\Local\om.c-test\om.c-event" ); + InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); + status = pNtOpenEvent( &h2, GENERIC_ALL, &attr ); + ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenEvent failed %x\n", status ); + pRtlFreeUnicodeString( &str ); + pNtClose( h ); + pNtClose( dir1 ); + str.Buffer = buffer; str.MaximumLength = sizeof(buffer); len = 0xdeadbeef; @@ -463,22 +1044,26 @@ error:
pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); - DIR_TEST_OPEN_SUCCESS(&dir) + status = pNtOpenDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status ); pRtlFreeUnicodeString(&str);
InitializeObjectAttributes(&attr, NULL, 0, dir, NULL); - DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_NAME_INVALID) + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenDirectoryObject got %08x\n", status );
InitializeObjectAttributes(&attr, &str, 0, dir, NULL); - DIR_TEST_CREATE_OPEN_SUCCESS(h, "") - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\", STATUS_OBJECT_PATH_SYNTAX_BAD) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "\om.c-test\", STATUS_OBJECT_PATH_SYNTAX_BAD) - DIR_TEST_CREATE_OPEN_FAILURE(&h, "om.c-test\", STATUS_OBJECT_PATH_NOT_FOUND) + DIR_TEST_CREATE_OPEN( "", STATUS_SUCCESS ); + DIR_TEST_CREATE_OPEN( "\", STATUS_OBJECT_PATH_SYNTAX_BAD ); + DIR_TEST_CREATE_OPEN( "\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD ); + DIR_TEST_CREATE_OPEN( "\om.c-test\", STATUS_OBJECT_PATH_SYNTAX_BAD ); + DIR_TEST_CREATE_OPEN( "om.c-test\", STATUS_OBJECT_PATH_NOT_FOUND );
pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test"); - DIR_TEST_CREATE_SUCCESS(&dir1) - DIR_TEST_OPEN_SUCCESS(&h) + status = pNtCreateDirectoryObject( &dir1, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status ); pRtlFreeUnicodeString(&str);
pNtClose(h); @@ -488,23 +1073,28 @@ error: /* Nested directories */ pRtlCreateUnicodeStringFromAsciiz(&str, "\"); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); - DIR_TEST_OPEN_SUCCESS(&dir) + status = pNtOpenDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status ); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); - DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) + status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenDirectoryObject got %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(dir);
InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects\om.c-test"); - DIR_TEST_CREATE_SUCCESS(&dir) + status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects\om.c-test\one more level"); - DIR_TEST_CREATE_SUCCESS(&h) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(h); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "one more level"); - DIR_TEST_CREATE_SUCCESS(&h) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(h);
@@ -514,15 +1104,18 @@ error: { InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects\Global\om.c-test"); - DIR_TEST_CREATE_SUCCESS(&dir) + status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pRtlFreeUnicodeString(&str); pRtlCreateUnicodeStringFromAsciiz(&str, "\BaseNamedObjects\Local\om.c-test\one more level"); - DIR_TEST_CREATE_SUCCESS(&h) + status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(h); InitializeObjectAttributes(&attr, &str, 0, dir, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "one more level"); - DIR_TEST_CREATE_SUCCESS(&dir) ... 4309 lines suppressed ...