Index: modules/rostests/winetests/ntdll/directory.c =================================================================== --- modules/rostests/winetests/ntdll/directory.c (revision 71788) +++ modules/rostests/winetests/ntdll/directory.c (working copy) @@ -34,6 +34,7 @@ #define WIN32_NO_STATUS #include "wine/test.h" +#include "winnls.h" #include "wine/winternl.h" static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); @@ -40,10 +41,13 @@ 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 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 @@ { 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,18 +156,18 @@ 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, @@ -159,17 +174,19 @@ 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 @@ 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 @@ 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,236 @@ 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_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: + 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; + 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); - pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA, strlen(testdirA)+1); if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL)) { ok(0, "RtlDosPathNametoNtPathName_U failed\n"); @@ -252,13 +479,11 @@ 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); @@ -265,8 +490,239 @@ 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 %x%08x\n", + (DWORD)(pos_info.CurrentByteOffset.QuadPart >> 32), (DWORD)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 %x%08x\n", + (DWORD)(pos_info.CurrentByteOffset.QuadPart >> 32), (DWORD)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 %x%08x\n", + (DWORD)(pos_info.CurrentByteOffset.QuadPart >> 32), (DWORD)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 %x%08x\n", + (DWORD)(pos_info.CurrentByteOffset.QuadPart >> 32), (DWORD)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); } @@ -415,6 +871,7 @@ START_TEST(directory) { + WCHAR sysdir[MAX_PATH]; HMODULE hntdll = GetModuleHandleA("ntdll.dll"); if (!hntdll) { @@ -425,14 +882,19 @@ 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(); Index: modules/rostests/winetests/ntdll/exception.c =================================================================== --- modules/rostests/winetests/ntdll/exception.c (revision 71788) +++ modules/rostests/winetests/ntdll/exception.c (working copy) @@ -221,6 +221,11 @@ { { 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; @@ -475,7 +480,7 @@ 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,21 +489,24 @@ ok( rec->ExceptionCode == except->status || (except->alt_status != 0 && rec->ExceptionCode == except->alt_status), "%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode, except->status ); - ok( rec->ExceptionAddress == (char*)code_mem + except->offset, - "%u: Wrong exception address %p/%p\n", entry, - rec->ExceptionAddress, (char*)code_mem + except->offset ); + ok( 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->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 ); - } + 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 */ if (except->nb_params == 2 && except->params[1] >= 0xfffffffd) @@ -532,7 +540,7 @@ 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; @@ -941,6 +949,24 @@ } 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, EXCEPTION_INVALID_HANDLE); @@ -947,7 +973,7 @@ 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,23 +1061,26 @@ 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 */ } + else + ok(FALSE, "unexpected stage %x\n", *stage); - context->Eip += 3; /* skip divps */ - return ExceptionContinueExecution; } @@ -1058,6 +1087,7 @@ 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,12 +1098,27 @@ 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 */ +}; + static const BYTE sse_check[] = { 0x0f, 0x58, 0xc8, /* addps %xmm0,%xmm1 */ 0xc3, /* ret */ @@ -1097,7 +1142,14 @@ 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 @@ -1325,6 +1377,8 @@ #elif defined(__x86_64__) +#define is_wow64 0 + #define UNW_FLAG_NHANDLER 0 #define UNW_FLAG_EHANDLER 1 #define UNW_FLAG_UHANDLER 2 @@ -1717,6 +1771,50 @@ #endif /* __x86_64__ */ #if defined(__i386__) || defined(__x86_64__) + +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; + 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); + } +} + static DWORD outputdebugstring_exceptions; static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) @@ -1750,6 +1848,7 @@ outputdebugstring_exceptions = 0; OutputDebugStringA("Hello World"); + ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n", outputdebugstring_exceptions, numexc); @@ -1805,6 +1904,236 @@ 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) @@ -1973,8 +2302,16 @@ test_stage = 6; test_ripevent(1); test_stage = 7; + 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 = 8; + test_stage = 12; test_closehandle(1); } else @@ -1987,8 +2324,11 @@ 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(); @@ -2007,8 +2347,11 @@ pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll, "RtlLookupFunctionEntry" ); + 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(); @@ -2020,5 +2363,5 @@ #endif - VirtualFree(code_mem, 0, MEM_FREE); + VirtualFree(code_mem, 0, MEM_RELEASE); } Index: modules/rostests/winetests/ntdll/info.c =================================================================== --- modules/rostests/winetests/ntdll/info.c (revision 71788) +++ modules/rostests/winetests/ntdll/info.c (working copy) @@ -23,6 +23,7 @@ #include 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 +37,7 @@ 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,6 +58,8 @@ { /* 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"); @@ -78,8 +82,16 @@ /* 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 +300,7 @@ /* 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 +486,15 @@ 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; @@ -493,31 +507,41 @@ 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); + 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 ); + 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 in handle list\n" ); - 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 ); - 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" ); + 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); HeapFree( GetProcessHeap(), 0, shi); } @@ -684,6 +708,110 @@ 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; @@ -1070,7 +1198,7 @@ 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); @@ -1293,27 +1421,27 @@ 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"); + /* 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); - 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; - - 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 +1450,123 @@ 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); + ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status); + ok(debug_flags == TRUE, "Expected flag TRUE, got %x.\n", debug_flags); - status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags, - &debug_flags, sizeof(debug_flags), NULL); - ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "NtQueryInformationProcess failed, status %#x.\n", status); - ok(debug_flags == FALSE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected flag FALSE, got %x.\n", debug_flags); - - for (;;) + 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 = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE); - ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError()); - if (!ret) break; + ret = DebugActiveProcess(pi.dwProcessId); + ok(ret, "DebugActiveProcess failed, last error %#x.\n", GetLastError()); + expected_flags = FALSE; + } + + /* 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); + + 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()); } - - 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 +1645,7 @@ 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 +1659,7 @@ 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 +1682,7 @@ 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); @@ -1780,6 +1986,19 @@ 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); +} + START_TEST(info) { char **argv; @@ -1844,6 +2063,7 @@ /* 0x49 SystemLogicalProcessorInformation */ trace("Starting test_query_logicalproc()\n"); test_query_logicalproc(); + test_query_logicalprocex(); /* NtPowerInformation */ @@ -1911,4 +2131,7 @@ trace("Starting test_thread_start_address()\n"); test_thread_start_address(); + + trace("Starting test_query_data_alignment()\n"); + test_query_data_alignment(); } Index: modules/rostests/winetests/ntdll/ntdll_test.h =================================================================== --- modules/rostests/winetests/ntdll/ntdll_test.h (revision 71788) +++ modules/rostests/winetests/ntdll/ntdll_test.h (working copy) @@ -20,10 +20,6 @@ #include -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x500 /* For NTSTATUS */ -#endif - #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" Index: modules/rostests/winetests/ntdll/om.c =================================================================== --- modules/rostests/winetests/ntdll/om.c (revision 71788) +++ modules/rostests/winetests/ntdll/om.c (working copy) @@ -33,12 +33,25 @@ 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,6 +68,7 @@ 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 ); #define KEYEDEVENT_WAIT 0x0001 #define KEYEDEVENT_WAKE 0x0002 @@ -165,6 +179,16 @@ 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); } @@ -171,28 +195,19 @@ #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_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) -#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); - static BOOL is_correct_dir( HANDLE dir, const char *name ) { NTSTATUS status; @@ -262,10 +277,12 @@ 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 +373,529 @@ 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 +914,34 @@ "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 +963,43 @@ 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 +1037,26 @@ 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 +1066,28 @@ /* 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 +1097,18 @@ { 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) + status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status ); pRtlFreeUnicodeString(&str); pNtClose(h); pNtClose(dir); @@ -532,7 +1118,8 @@ InitializeObjectAttributes(&attr, &str, 0, 0, NULL); pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects"); - 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, &str, 0, dir, NULL); @@ -563,20 +1150,6 @@ pNtClose(dir); } -#define SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e2) \ - pRtlCreateUnicodeStringFromAsciiz(&str, n);\ - pRtlCreateUnicodeStringFromAsciiz(&target, t);\ - status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target);\ - ok(status == e || status == e2, \ - "NtCreateSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\ - status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr);\ - ok(status == e || status == e2, \ - "NtOpenSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\ - pRtlFreeUnicodeString(&target);\ - pRtlFreeUnicodeString(&str); - -#define SYMLNK_TEST_CREATE_OPEN_FAILURE(h,n,t,e) SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e) - static void test_symboliclink(void) { NTSTATUS status; @@ -587,7 +1160,13 @@ /* No name and/or no attributes */ InitializeObjectAttributes(&attr, NULL, 0, 0, NULL); - SYMLNK_TEST_CREATE_OPEN_FAILURE2(NULL, "", "", STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER) + pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices"); + status = pNtCreateSymbolicLinkObject( NULL, SYMBOLIC_LINK_QUERY, &attr, &target ); + ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, + "NtCreateSymbolicLinkObject got %08x\n", status ); + status = pNtOpenSymbolicLinkObject( NULL, SYMBOLIC_LINK_QUERY, &attr ); + ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER, + "NtOpenSymbolicLinkObject got %08x\n", status ); status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, NULL); ok(status == STATUS_ACCESS_VIOLATION, @@ -597,7 +1176,6 @@ "NtOpenSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status); /* No attributes */ - pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices"); status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, &target); ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_VIOLATION, /* nt4 */ "NtCreateSymbolicLinkObject failed(%08x)\n", status); @@ -634,14 +1212,46 @@ pRtlFreeUnicodeString(&str); pRtlFreeUnicodeString(&target); - SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", "->Somewhere", STATUS_OBJECT_PATH_SYNTAX_BAD) - SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID) - SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", "->Somewhere", STATUS_OBJECT_NAME_INVALID) - SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", "->Somewhere", STATUS_OBJECT_NAME_INVALID) - SYMLNK_TEST_CREATE_OPEN_FAILURE2(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere", - STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND) + pRtlCreateUnicodeStringFromAsciiz( &target, "->Somewhere"); + pRtlCreateUnicodeStringFromAsciiz( &str, "BaseNamedObjects" ); + status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateSymbolicLinkObject got %08x\n", status ); + status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenSymbolicLinkObject got %08x\n", status ); + pRtlFreeUnicodeString( &str ); + pRtlCreateUnicodeStringFromAsciiz( &str, "\\BaseNamedObjects\\" ); + status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtCreateSymbolicLinkObject got %08x\n", status ); + status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenSymbolicLinkObject got %08x\n", status ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "\\\\BaseNamedObjects" ); + status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtCreateSymbolicLinkObject got %08x\n", status ); + status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenSymbolicLinkObject got %08x\n", status ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "\\BaseNamedObjects\\\\om.c-test" ); + status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtCreateSymbolicLinkObject got %08x\n", status ); + status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenSymbolicLinkObject got %08x\n", status ); + pRtlFreeUnicodeString( &str ); + + pRtlCreateUnicodeStringFromAsciiz( &str, "\\BaseNamedObjects\\om.c-test\\" ); + status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target ); + ok( status == STATUS_OBJECT_NAME_INVALID || status == STATUS_OBJECT_PATH_NOT_FOUND, + "NtCreateSymbolicLinkObject got %08x\n", status ); + status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr ); + ok( status == STATUS_OBJECT_NAME_INVALID || status == STATUS_OBJECT_PATH_NOT_FOUND, + "NtOpenSymbolicLinkObject got %08x\n", status ); + pRtlFreeUnicodeString( &str ); + pRtlFreeUnicodeString(&target); + /* Compound test */ if (!(dir = get_base_dir())) { @@ -682,10 +1292,13 @@ char buffer[1024]; NTSTATUS status; ULONG len, expected_len; - UNICODE_STRING *str; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING path, *str; char dir[MAX_PATH], tmp_path[MAX_PATH], file1[MAX_PATH + 16]; LARGE_INTEGER size; + InitializeObjectAttributes( &attr, &path, 0, 0, 0 ); + handle = CreateEventA( NULL, FALSE, FALSE, "test_event" ); len = 0; @@ -715,9 +1328,12 @@ str = (UNICODE_STRING *)buffer; ok( sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR) == len, "unexpected len %u\n", len ); ok( str->Length >= sizeof(name), "unexpected len %u\n", str->Length ); + ok( len > sizeof(UNICODE_STRING) + sizeof("\\test_event") * sizeof(WCHAR), + "name too short %s\n", wine_dbgstr_w(str->Buffer) ); /* there can be a \\Sessions prefix in the name */ ok( !memcmp( str->Buffer + (str->Length - sizeof(name)) / sizeof(WCHAR), name, sizeof(name) ), "wrong name %s\n", wine_dbgstr_w(str->Buffer) ); + trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len ); len -= sizeof(WCHAR); status = pNtQueryObject( handle, ObjectNameInformation, buffer, len, &len ); @@ -851,6 +1467,64 @@ ok( str->Buffer && !memcmp( str->Buffer, type_section, sizeof(type_section) ), "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); pNtClose( handle ); + + handle = CreateMailslotA( "\\\\.\\mailslot\\test_mailslot", 100, 1000, NULL ); + ok( handle != INVALID_HANDLE_VALUE, "CreateMailslot failed err %u\n", GetLastError() ); + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS , "NtQueryObject returned %x\n", status ); + str = (UNICODE_STRING *)buffer; + ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR); + ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */ + "unexpected len %u\n", len ); + ok( len > sizeof(UNICODE_STRING) + sizeof("\\test_mailslot") * sizeof(WCHAR), + "name too short %s\n", wine_dbgstr_w(str->Buffer) ); + trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len ); + pNtClose( handle ); + + handle = CreateNamedPipeA( "\\\\.\\pipe\\test_pipe", PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE, + 1, 1000, 1000, 1000, NULL ); + ok( handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed err %u\n", GetLastError() ); + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS , "NtQueryObject returned %x\n", status ); + str = (UNICODE_STRING *)buffer; + ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR); + ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */ + "unexpected len %u\n", len ); + ok( len > sizeof(UNICODE_STRING) + sizeof("\\test_pipe") * sizeof(WCHAR), + "name too short %s\n", wine_dbgstr_w(str->Buffer) ); + trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len ); + pNtClose( handle ); + + pRtlCreateUnicodeStringFromAsciiz( &path, "\\REGISTRY\\Machine\\Software\\Classes" ); + status = pNtCreateKey( &handle, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 ); + ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED, + "NtCreateKey failed status %x\n", status ); + pRtlFreeUnicodeString( &path ); + if (status == STATUS_SUCCESS) + { + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS , "NtQueryObject returned %x\n", status ); + str = (UNICODE_STRING *)buffer; + todo_wine + ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR); + todo_wine + ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */ + "unexpected len %u\n", len ); + todo_wine + ok( len > sizeof(UNICODE_STRING) + sizeof("\\Classes") * sizeof(WCHAR), + "name too short %s\n", wine_dbgstr_w(str->Buffer) ); + trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len ); + pNtClose( handle ); + } } static void test_type_mismatch(void) @@ -1190,6 +1864,121 @@ CloseHandle(ov.hEvent); } +static DWORD WINAPI mutant_thread( void *arg ) +{ + MUTANT_BASIC_INFORMATION info; + NTSTATUS status; + HANDLE mutant; + DWORD ret; + + mutant = arg; + ret = WaitForSingleObject( mutant, 1000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret ); + + memset(&info, 0xcc, sizeof(info)); + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status ); + ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount ); + ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller ); + ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState ); + /* abandon mutant */ + + return 0; +} + +static void test_mutant(void) +{ + static const WCHAR name[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s', + '\\','t','e','s','t','_','m','u','t','a','n','t',0}; + MUTANT_BASIC_INFORMATION info; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + NTSTATUS status; + HANDLE mutant; + HANDLE thread; + DWORD ret; + ULONG len; + LONG prev; + + pRtlInitUnicodeString(&str, name); + InitializeObjectAttributes(&attr, &str, 0, 0, NULL); + status = pNtCreateMutant(&mutant, GENERIC_ALL, &attr, TRUE); + ok( status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status ); + + /* bogus */ + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, 0, NULL); + ok( status == STATUS_INFO_LENGTH_MISMATCH, + "Failed to NtQueryMutant, expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status ); + status = pNtQueryMutant(mutant, 0x42, &info, sizeof(info), NULL); + ok( status == STATUS_INVALID_INFO_CLASS || broken(status == STATUS_NOT_IMPLEMENTED), /* 32-bit on Vista/2k8 */ + "Failed to NtQueryMutant, expected STATUS_INVALID_INFO_CLASS, got %08x\n", status ); + status = pNtQueryMutant((HANDLE)0xdeadbeef, MutantBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_INVALID_HANDLE, + "Failed to NtQueryMutant, expected STATUS_INVALID_HANDLE, got %08x\n", status ); + + /* new */ + len = -1; + memset(&info, 0xcc, sizeof(info)); + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), &len); + ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status ); + ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount ); + ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller ); + ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState ); + ok( len == sizeof(info), "got %u\n", len ); + + ret = WaitForSingleObject( mutant, 1000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret ); + + memset(&info, 0xcc, sizeof(info)); + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status ); + ok( info.CurrentCount == -1, "expected -1, got %d\n", info.CurrentCount ); + ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller ); + ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState ); + + prev = 0xdeadbeef; + status = pNtReleaseMutant(mutant, &prev); + ok( status == STATUS_SUCCESS, "NtQueryRelease failed %08x\n", status ); + ok( prev == -1, "NtQueryRelease failed, expected -1, got %d\n", prev ); + + prev = 0xdeadbeef; + status = pNtReleaseMutant(mutant, &prev); + ok( status == STATUS_SUCCESS, "NtQueryRelease failed %08x\n", status ); + ok( prev == 0, "NtQueryRelease failed, expected 0, got %d\n", prev ); + + memset(&info, 0xcc, sizeof(info)); + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status ); + ok( info.CurrentCount == 1, "expected 1, got %d\n", info.CurrentCount ); + ok( info.OwnedByCaller == FALSE, "expected FALSE, got %d\n", info.OwnedByCaller ); + ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState ); + + /* abandoned */ + thread = CreateThread( NULL, 0, mutant_thread, mutant, 0, NULL ); + ret = WaitForSingleObject( thread, 1000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret ); + CloseHandle( thread ); + + memset(&info, 0xcc, sizeof(info)); + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status ); + ok( info.CurrentCount == 1, "expected 0, got %d\n", info.CurrentCount ); + ok( info.OwnedByCaller == FALSE, "expected FALSE, got %d\n", info.OwnedByCaller ); + ok( info.AbandonedState == TRUE, "expected TRUE, got %d\n", info.AbandonedState ); + + ret = WaitForSingleObject( mutant, 1000 ); + ok( ret == WAIT_ABANDONED_0, "WaitForSingleObject failed %08x\n", ret ); + + memset(&info, 0xcc, sizeof(info)); + status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status ); + ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount ); + ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller ); + ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState ); + + NtClose( mutant ); +} + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -1206,11 +1995,19 @@ pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent"); + pNtCreateJobObject = (void *)GetProcAddress(hntdll, "NtCreateJobObject"); + pNtOpenJobObject = (void *)GetProcAddress(hntdll, "NtOpenJobObject"); + pNtCreateKey = (void *)GetProcAddress(hntdll, "NtCreateKey"); + pNtOpenKey = (void *)GetProcAddress(hntdll, "NtOpenKey"); + pNtDeleteKey = (void *)GetProcAddress(hntdll, "NtDeleteKey"); + pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtCreateMutant = (void *)GetProcAddress(hntdll, "NtCreateMutant"); pNtOpenEvent = (void *)GetProcAddress(hntdll, "NtOpenEvent"); pNtQueryEvent = (void *)GetProcAddress(hntdll, "NtQueryEvent"); pNtPulseEvent = (void *)GetProcAddress(hntdll, "NtPulseEvent"); pNtOpenMutant = (void *)GetProcAddress(hntdll, "NtOpenMutant"); + pNtQueryMutant = (void *)GetProcAddress(hntdll, "NtQueryMutant"); + pNtReleaseMutant = (void *)GetProcAddress(hntdll, "NtReleaseMutant"); pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); @@ -1221,8 +2018,11 @@ pNtCreateSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtCreateSymbolicLinkObject"); pNtQuerySymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtQuerySymbolicLinkObject"); pNtCreateSemaphore = (void *)GetProcAddress(hntdll, "NtCreateSemaphore"); + pNtOpenSemaphore = (void *)GetProcAddress(hntdll, "NtOpenSemaphore"); pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer"); + pNtOpenTimer = (void *)GetProcAddress(hntdll, "NtOpenTimer"); pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection"); + pNtOpenSection = (void *)GetProcAddress(hntdll, "NtOpenSection"); pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject"); pNtReleaseSemaphore = (void *)GetProcAddress(hntdll, "NtReleaseSemaphore"); pNtCreateKeyedEvent = (void *)GetProcAddress(hntdll, "NtCreateKeyedEvent"); @@ -1230,15 +2030,18 @@ pNtWaitForKeyedEvent = (void *)GetProcAddress(hntdll, "NtWaitForKeyedEvent"); pNtReleaseKeyedEvent = (void *)GetProcAddress(hntdll, "NtReleaseKeyedEvent"); pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); + pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); test_case_sensitive(); test_namespace_pipe(); test_name_collisions(); + test_name_limits(); test_directory(); test_symboliclink(); test_query_object(); test_type_mismatch(); test_event(); + test_mutant(); test_keyed_events(); test_null_device(); }