mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-27 03:43:36 +00:00
[NTDLL_WINETEST] Sync with Wine Staging 2.16. CORE-13762
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
include_directories(BEFORE ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
|
||||
remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502)
|
||||
add_definitions(-D__WINESRC__)
|
||||
add_definitions(-D__WINESRC__ -DWINETEST_USE_DBGSTR_LONGLONG)
|
||||
|
||||
list(APPEND SOURCE
|
||||
atom.c
|
||||
@@ -17,6 +17,7 @@ list(APPEND SOURCE
|
||||
path.c
|
||||
pipe.c
|
||||
port.c
|
||||
process.c
|
||||
reg.c
|
||||
rtl.c
|
||||
rtlbitmap.c
|
||||
|
||||
@@ -34,16 +34,20 @@
|
||||
#define WIN32_NO_STATUS
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winnls.h"
|
||||
#include "wine/winternl.h"
|
||||
|
||||
static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
|
||||
static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG );
|
||||
static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,
|
||||
PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
|
||||
static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,LONG,FILE_INFORMATION_CLASS);
|
||||
static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
|
||||
static BOOLEAN (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING,LPCSTR);
|
||||
static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* );
|
||||
static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR );
|
||||
static VOID (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING );
|
||||
static LONG (WINAPI *pRtlCompareUnicodeString)( const UNICODE_STRING*, const UNICODE_STRING*,BOOLEAN );
|
||||
static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
|
||||
LPCSTR src, DWORD srclen );
|
||||
static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirection)( BOOLEAN enable );
|
||||
@@ -53,47 +57,56 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG *
|
||||
static struct testfile_s {
|
||||
BOOL attr_done; /* set if attributes were tested for this file already */
|
||||
const DWORD attr; /* desired attribute */
|
||||
const char *name; /* filename to use */
|
||||
WCHAR name[20]; /* filename to use */
|
||||
const char *target; /* what to point to (only for reparse pts) */
|
||||
const char *description; /* for error messages */
|
||||
int nfound; /* How many were found (expect 1) */
|
||||
WCHAR nameW[20]; /* unicode version of name (filled in later) */
|
||||
} testfiles[] = {
|
||||
{ 0, FILE_ATTRIBUTE_NORMAL, "n.tmp", NULL, "normal" },
|
||||
{ 0, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" },
|
||||
{ 0, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" },
|
||||
{ 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" },
|
||||
{ 0, FILE_ATTRIBUTE_DIRECTORY, ".", NULL, ". directory" },
|
||||
{ 0, FILE_ATTRIBUTE_DIRECTORY, "..", NULL, ".. directory" },
|
||||
{ 0, 0, NULL }
|
||||
{ 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" },
|
||||
{ 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" },
|
||||
{ 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" },
|
||||
{ 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" },
|
||||
{ 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" },
|
||||
{ 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" },
|
||||
{ 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" },
|
||||
{ 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" },
|
||||
{ 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" },
|
||||
{ 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" }
|
||||
};
|
||||
static const int max_test_dir_size = 20; /* size of above plus some for .. etc */
|
||||
static const int test_dir_count = sizeof(testfiles) / sizeof(testfiles[0]);
|
||||
static const int max_test_dir_size = sizeof(testfiles) / sizeof(testfiles[0]) + 5; /* size of above plus some for .. etc */
|
||||
|
||||
static const WCHAR dummyW[] = {'d','u','m','m','y',0};
|
||||
static const WCHAR dotW[] = {'.',0};
|
||||
static const WCHAR dotdotW[] = {'.','.',0};
|
||||
static const WCHAR backslashW[] = {'\\',0};
|
||||
|
||||
/* Create a test directory full of attribute test files, clear counts */
|
||||
static void set_up_attribute_test(const char *testdirA)
|
||||
static void set_up_attribute_test(const WCHAR *testdir)
|
||||
{
|
||||
int i;
|
||||
BOOL ret;
|
||||
|
||||
ret = CreateDirectoryA(testdirA, NULL);
|
||||
ok(ret, "couldn't create dir '%s', error %d\n", testdirA, GetLastError());
|
||||
ret = CreateDirectoryW(testdir, NULL);
|
||||
ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(testdir), GetLastError());
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
char buf[MAX_PATH];
|
||||
pRtlMultiByteToUnicodeN(testfiles[i].nameW, sizeof(testfiles[i].nameW), NULL, testfiles[i].name, strlen(testfiles[i].name)+1);
|
||||
for (i=0; i < test_dir_count; i++) {
|
||||
WCHAR buf[MAX_PATH];
|
||||
|
||||
if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name, "..") == 0)
|
||||
if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0)
|
||||
continue;
|
||||
sprintf(buf, "%s\\%s", testdirA, testfiles[i].name);
|
||||
lstrcpyW( buf, testdir );
|
||||
lstrcatW( buf, backslashW );
|
||||
lstrcatW( buf, testfiles[i].name );
|
||||
if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
ret = CreateDirectoryA(buf, NULL);
|
||||
ok(ret, "couldn't create dir '%s', error %d\n", buf, GetLastError());
|
||||
ret = CreateDirectoryW(buf, NULL);
|
||||
ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(buf), GetLastError());
|
||||
} else {
|
||||
HANDLE h = CreateFileA(buf,
|
||||
HANDLE h = CreateFileW(buf,
|
||||
GENERIC_READ|GENERIC_WRITE,
|
||||
0, NULL, CREATE_ALWAYS,
|
||||
testfiles[i].attr, 0);
|
||||
ok( h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf );
|
||||
ok( h != INVALID_HANDLE_VALUE, "failed to create temp file %s\n", wine_dbgstr_w(buf) );
|
||||
CloseHandle(h);
|
||||
}
|
||||
}
|
||||
@@ -103,32 +116,34 @@ static void reset_found_files(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; testfiles[i].name; i++)
|
||||
for (i = 0; i < test_dir_count; i++)
|
||||
testfiles[i].nfound = 0;
|
||||
}
|
||||
|
||||
/* Remove the given test directory and the attribute test files, if any */
|
||||
static void tear_down_attribute_test(const char *testdirA)
|
||||
static void tear_down_attribute_test(const WCHAR *testdir)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
for (i = 0; i < test_dir_count; i++) {
|
||||
int ret;
|
||||
char buf[MAX_PATH];
|
||||
if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name, "..") == 0)
|
||||
WCHAR buf[MAX_PATH];
|
||||
if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0)
|
||||
continue;
|
||||
sprintf(buf, "%s\\%s", testdirA, testfiles[i].name);
|
||||
lstrcpyW( buf, testdir );
|
||||
lstrcatW( buf, backslashW );
|
||||
lstrcatW( buf, testfiles[i].name );
|
||||
if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
ret = RemoveDirectoryA(buf);
|
||||
ret = RemoveDirectoryW(buf);
|
||||
ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"Failed to rmdir %s, error %d\n", buf, GetLastError());
|
||||
"Failed to rmdir %s, error %d\n", wine_dbgstr_w(buf), GetLastError());
|
||||
} else {
|
||||
ret = DeleteFileA(buf);
|
||||
ret = DeleteFileW(buf);
|
||||
ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND),
|
||||
"Failed to rm %s, error %d\n", buf, GetLastError());
|
||||
"Failed to rm %s, error %d\n", wine_dbgstr_w(buf), GetLastError());
|
||||
}
|
||||
}
|
||||
RemoveDirectoryA(testdirA);
|
||||
RemoveDirectoryW(testdir);
|
||||
}
|
||||
|
||||
/* Match one found file against testfiles[], increment count if found */
|
||||
@@ -141,35 +156,37 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info)
|
||||
WCHAR *nameW = dir_info->FileName;
|
||||
int namelen = dir_info->FileNameLength / sizeof(WCHAR);
|
||||
|
||||
for (i=0; testfiles[i].name; i++) {
|
||||
int len = strlen(testfiles[i].name);
|
||||
if (namelen != len || memcmp(nameW, testfiles[i].nameW, len*sizeof(WCHAR)))
|
||||
for (i = 0; i < test_dir_count; i++) {
|
||||
int len = lstrlenW(testfiles[i].name);
|
||||
if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR)))
|
||||
continue;
|
||||
if (!testfiles[i].attr_done) {
|
||||
ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib);
|
||||
ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib);
|
||||
testfiles[i].attr_done = TRUE;
|
||||
}
|
||||
testfiles[i].nfound++;
|
||||
break;
|
||||
}
|
||||
ok(testfiles[i].name != NULL, "unexpected file found\n");
|
||||
ok(i < test_dir_count, "unexpected file found %s\n", wine_dbgstr_wn(dir_info->FileName, namelen));
|
||||
}
|
||||
|
||||
static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char *testdirA,
|
||||
UNICODE_STRING *mask,
|
||||
BOOLEAN single_entry, BOOLEAN restart_flag)
|
||||
{
|
||||
HANDLE dirh;
|
||||
UNICODE_STRING dummy_mask;
|
||||
HANDLE dirh, new_dirh;
|
||||
IO_STATUS_BLOCK io;
|
||||
UINT data_pos, data_size;
|
||||
UINT data_len; /* length of dir data */
|
||||
BYTE data[8192]; /* directory data */
|
||||
FILE_BOTH_DIRECTORY_INFORMATION *dir_info;
|
||||
DWORD status;
|
||||
NTSTATUS status;
|
||||
int numfiles;
|
||||
int i;
|
||||
|
||||
reset_found_files();
|
||||
pRtlInitUnicodeString( &dummy_mask, dummyW );
|
||||
|
||||
data_size = mask ? offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ) : sizeof(data);
|
||||
|
||||
@@ -182,12 +199,18 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
||||
return;
|
||||
}
|
||||
|
||||
pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, restart_flag );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, restart_flag );
|
||||
ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||
data_len = io.Information;
|
||||
ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n");
|
||||
|
||||
DuplicateHandle( GetCurrentProcess(), dirh, GetCurrentProcess(), &new_dirh,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS );
|
||||
pNtClose(dirh);
|
||||
|
||||
data_pos = 0;
|
||||
numfiles = 0;
|
||||
while ((data_pos < data_len) && (numfiles < max_test_dir_size)) {
|
||||
@@ -196,11 +219,12 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
||||
tally_test_file(dir_info);
|
||||
|
||||
if (dir_info->NextEntryOffset == 0) {
|
||||
pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, mask, FALSE );
|
||||
if (U(io).Status == STATUS_NO_MORE_FILES)
|
||||
break;
|
||||
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( new_dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, single_entry, &dummy_mask, FALSE );
|
||||
ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status);
|
||||
if (status == STATUS_NO_MORE_FILES) break;
|
||||
ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||
data_len = io.Information;
|
||||
if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION))
|
||||
break;
|
||||
@@ -213,33 +237,238 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
|
||||
ok(numfiles < max_test_dir_size, "too many loops\n");
|
||||
|
||||
if (mask)
|
||||
for (i=0; testfiles[i].name; i++)
|
||||
ok(testfiles[i].nfound == (testfiles[i].nameW == mask->Buffer),
|
||||
for (i = 0; i < test_dir_count; i++)
|
||||
ok(testfiles[i].nfound == (testfiles[i].name == mask->Buffer),
|
||||
"Wrong number %d of %s files found (single_entry=%d,mask=%s)\n",
|
||||
testfiles[i].nfound, testfiles[i].description, single_entry,
|
||||
wine_dbgstr_wn(mask->Buffer, mask->Length/sizeof(WCHAR) ));
|
||||
else
|
||||
for (i=0; testfiles[i].name; i++)
|
||||
for (i = 0; i < test_dir_count; i++)
|
||||
ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found (single_entry=%d,restart=%d)\n",
|
||||
testfiles[i].nfound, testfiles[i].description, single_entry, restart_flag);
|
||||
pNtClose(dirh);
|
||||
pNtClose(new_dirh);
|
||||
}
|
||||
|
||||
static void test_directory_sort( const WCHAR *testdir )
|
||||
{
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
UNICODE_STRING ntdirname;
|
||||
IO_STATUS_BLOCK io;
|
||||
UINT data_pos, data_len, count;
|
||||
BYTE data[8192];
|
||||
WCHAR prev[MAX_PATH], name[MAX_PATH];
|
||||
UNICODE_STRING prev_str, name_str;
|
||||
FILE_BOTH_DIRECTORY_INFORMATION *info;
|
||||
NTSTATUS status;
|
||||
HANDLE handle;
|
||||
int res;
|
||||
|
||||
if (!pRtlDosPathNameToNtPathName_U( testdir, &ntdirname, NULL, NULL ))
|
||||
{
|
||||
ok(0, "RtlDosPathNametoNtPathName_U failed\n");
|
||||
return;
|
||||
}
|
||||
InitializeObjectAttributes( &attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||
status = pNtOpenFile( &handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE );
|
||||
ok(status == STATUS_SUCCESS, "failed to open dir %s\n", wine_dbgstr_w(testdir) );
|
||||
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, data, sizeof(data),
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status );
|
||||
data_len = io.Information;
|
||||
ok( data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n" );
|
||||
data_pos = 0;
|
||||
count = 0;
|
||||
|
||||
while (data_pos < data_len)
|
||||
{
|
||||
info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos);
|
||||
|
||||
memcpy( name, info->FileName, info->FileNameLength );
|
||||
name[info->FileNameLength / sizeof(WCHAR)] = 0;
|
||||
switch (count)
|
||||
{
|
||||
case 0: /* first entry must be '.' */
|
||||
ok( !lstrcmpW( name, dotW ), "wrong name %s\n", wine_dbgstr_w( name ));
|
||||
break;
|
||||
case 1: /* second entry must be '..' */
|
||||
ok( !lstrcmpW( name, dotdotW ), "wrong name %s\n", wine_dbgstr_w( name ));
|
||||
break;
|
||||
case 2: /* nothing to compare against */
|
||||
break;
|
||||
default:
|
||||
pRtlInitUnicodeString( &prev_str, prev );
|
||||
pRtlInitUnicodeString( &name_str, name );
|
||||
res = pRtlCompareUnicodeString( &prev_str, &name_str, TRUE );
|
||||
ok( res < 0, "wrong result %d %s %s\n", res, wine_dbgstr_w( prev ), wine_dbgstr_w( name ));
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
lstrcpyW( prev, name );
|
||||
|
||||
if (info->NextEntryOffset == 0)
|
||||
{
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, sizeof(data),
|
||||
FileBothDirectoryInformation, FALSE, NULL, FALSE );
|
||||
ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status);
|
||||
if (status == STATUS_NO_MORE_FILES) break;
|
||||
ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n", status );
|
||||
data_len = io.Information;
|
||||
data_pos = 0;
|
||||
}
|
||||
else data_pos += info->NextEntryOffset;
|
||||
}
|
||||
|
||||
pNtClose( handle );
|
||||
pRtlFreeUnicodeString( &ntdirname );
|
||||
}
|
||||
|
||||
static void test_NtQueryDirectoryFile_classes( HANDLE handle, UNICODE_STRING *mask )
|
||||
{
|
||||
IO_STATUS_BLOCK io;
|
||||
UINT data_size;
|
||||
ULONG data[256];
|
||||
NTSTATUS status;
|
||||
int class;
|
||||
|
||||
for (class = 0; class < FileMaximumInformation; class++)
|
||||
{
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
data_size = 0;
|
||||
memset( data, 0x55, sizeof(data) );
|
||||
|
||||
status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size,
|
||||
class, FALSE, mask, TRUE );
|
||||
ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class, U(io).Status );
|
||||
ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class, U(io).Information );
|
||||
ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] );
|
||||
|
||||
switch (class)
|
||||
{
|
||||
case FileIdGlobalTxDirectoryInformation:
|
||||
case FileIdExtdDirectoryInformation:
|
||||
case FileIdExtdBothDirectoryInformation:
|
||||
if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED) continue;
|
||||
/* fall through */
|
||||
case FileDirectoryInformation:
|
||||
case FileFullDirectoryInformation:
|
||||
case FileBothDirectoryInformation:
|
||||
case FileNamesInformation:
|
||||
case FileIdBothDirectoryInformation:
|
||||
case FileIdFullDirectoryInformation:
|
||||
case FileObjectIdInformation:
|
||||
case FileQuotaInformation:
|
||||
case FileReparsePointInformation:
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "%u: wrong status %x\n", class, status );
|
||||
break;
|
||||
default:
|
||||
ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED,
|
||||
"%u: wrong status %x\n", class, status );
|
||||
continue;
|
||||
}
|
||||
|
||||
for (data_size = 1; data_size < sizeof(data); data_size++)
|
||||
{
|
||||
status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size,
|
||||
class, FALSE, mask, TRUE );
|
||||
if (status == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, U(io).Status );
|
||||
ok( U(io).Information == data_size, "%u: wrong info %lx\n", class, U(io).Information );
|
||||
ok(data[0] == 0, "%u: wrong offset %x\n", class, data[0] );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class, U(io).Status );
|
||||
ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class, U(io).Information );
|
||||
ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] );
|
||||
}
|
||||
if (status != STATUS_INFO_LENGTH_MISMATCH) break;
|
||||
}
|
||||
|
||||
switch (class)
|
||||
{
|
||||
case FileDirectoryInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileFullDirectoryInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_FULL_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileBothDirectoryInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileNamesInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileIdBothDirectoryInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_ID_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileIdFullDirectoryInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_ID_FULL_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileIdGlobalTxDirectoryInformation:
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == ((offsetof( FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileObjectIdInformation:
|
||||
ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == sizeof(FILE_OBJECTID_INFORMATION), "%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileQuotaInformation:
|
||||
ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == sizeof(FILE_QUOTA_INFORMATION), "%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
case FileReparsePointInformation:
|
||||
ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status );
|
||||
ok( data_size == sizeof(FILE_REPARSE_POINT_INFORMATION), "%u: wrong size %u\n", class, data_size );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_NtQueryDirectoryFile(void)
|
||||
{
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
UNICODE_STRING ntdirname;
|
||||
UNICODE_STRING ntdirname, mask;
|
||||
char testdirA[MAX_PATH];
|
||||
WCHAR testdirW[MAX_PATH];
|
||||
int i;
|
||||
IO_STATUS_BLOCK io;
|
||||
WCHAR short_name[12];
|
||||
UINT data_size;
|
||||
BYTE data[8192];
|
||||
FILE_BOTH_DIRECTORY_INFORMATION *next, *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data;
|
||||
FILE_POSITION_INFORMATION pos_info;
|
||||
FILE_NAMES_INFORMATION *names;
|
||||
const WCHAR *filename = fbdi->FileName;
|
||||
NTSTATUS status;
|
||||
HANDLE dirh;
|
||||
|
||||
/* Clean up from prior aborted run, if any, then set up test files */
|
||||
ok(GetTempPathA(MAX_PATH, testdirA), "couldn't get temp dir\n");
|
||||
strcat(testdirA, "NtQueryDirectoryFile.tmp");
|
||||
tear_down_attribute_test(testdirA);
|
||||
set_up_attribute_test(testdirA);
|
||||
|
||||
pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA, strlen(testdirA)+1);
|
||||
tear_down_attribute_test(testdirW);
|
||||
set_up_attribute_test(testdirW);
|
||||
|
||||
if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL))
|
||||
{
|
||||
ok(0, "RtlDosPathNametoNtPathName_U failed\n");
|
||||
@@ -252,21 +481,250 @@ static void test_NtQueryDirectoryFile(void)
|
||||
test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, TRUE);
|
||||
test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, FALSE);
|
||||
|
||||
for (i = 0; testfiles[i].name; i++)
|
||||
for (i = 0; i < test_dir_count; i++)
|
||||
{
|
||||
UNICODE_STRING mask;
|
||||
|
||||
if (testfiles[i].nameW[0] == '.') continue; /* . and .. as masks are broken on Windows */
|
||||
mask.Buffer = testfiles[i].nameW;
|
||||
mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].nameW) * sizeof(WCHAR);
|
||||
if (testfiles[i].name[0] == '.') continue; /* . and .. as masks are broken on Windows */
|
||||
mask.Buffer = testfiles[i].name;
|
||||
mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].name) * sizeof(WCHAR);
|
||||
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE);
|
||||
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, FALSE);
|
||||
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, TRUE);
|
||||
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/* short path passed as mask */
|
||||
status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE);
|
||||
ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
skip("can't test if we can't open the directory\n");
|
||||
return;
|
||||
}
|
||||
status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status );
|
||||
ok( pos_info.CurrentByteOffset.QuadPart == 0, "wrong pos %s\n",
|
||||
wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart));
|
||||
|
||||
pos_info.CurrentByteOffset.QuadPart = 0xbeef;
|
||||
status = pNtSetInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status );
|
||||
|
||||
status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status );
|
||||
ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n",
|
||||
wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart));
|
||||
|
||||
mask.Buffer = testfiles[0].name;
|
||||
mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].name) * sizeof(WCHAR);
|
||||
data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, FALSE);
|
||||
ok(status == STATUS_SUCCESS, "failed to query directory; status %x\n", status);
|
||||
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status);
|
||||
ok(fbdi->ShortName[0], "ShortName is empty\n");
|
||||
|
||||
status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status );
|
||||
ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n",
|
||||
wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) );
|
||||
|
||||
mask.Length = mask.MaximumLength = fbdi->ShortNameLength;
|
||||
memcpy(short_name, fbdi->ShortName, mask.Length);
|
||||
mask.Buffer = short_name;
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
ok(status == STATUS_SUCCESS, "failed to query directory status %x\n", status);
|
||||
ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n", U(io).Status);
|
||||
ok(U(io).Information == offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[lstrlenW(testfiles[0].name)]),
|
||||
"wrong info %lx\n", U(io).Information);
|
||||
ok(fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) &&
|
||||
!memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength),
|
||||
"incorrect long file name: %s\n", wine_dbgstr_wn(fbdi->FileName,
|
||||
fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status );
|
||||
ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n",
|
||||
wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) );
|
||||
|
||||
/* tests with short buffer */
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] );
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == data_size || broken( U(io).Information == 0),
|
||||
"wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name) * sizeof(WCHAR),
|
||||
"wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( filename[0] == testfiles[0].name[0], "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
ok( filename[1] == 0x5555, "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
test_NtQueryDirectoryFile_classes( dirh, &mask );
|
||||
|
||||
/* mask may or may not be ignored when restarting the search */
|
||||
pRtlInitUnicodeString( &mask, dummyW );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] );
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
ok( status == STATUS_SUCCESS || status == STATUS_NO_MORE_FILES, "wrong status %x\n", status );
|
||||
ok( U(io).Status == status, "wrong status %x / %x\n", U(io).Status, status );
|
||||
if (!status)
|
||||
ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) &&
|
||||
!memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength),
|
||||
"incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
pNtClose(dirh);
|
||||
|
||||
status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE);
|
||||
ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA);
|
||||
|
||||
memset( data, 0x55, data_size );
|
||||
data_size = sizeof(data);
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE);
|
||||
ok(status == STATUS_SUCCESS, "wrong status %x\n", status);
|
||||
ok(U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status);
|
||||
ok(U(io).Information > 0 && U(io).Information < data_size, "wrong info %lx\n", U(io).Information);
|
||||
ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
|
||||
ok( next->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ) + 7) & ~7),
|
||||
"wrong offset %x\n", next->NextEntryOffset );
|
||||
ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength );
|
||||
filename = next->FileName;
|
||||
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
"wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
next = (FILE_BOTH_DIRECTORY_INFORMATION *)&fbdi->FileName[1];
|
||||
ok( next->NextEntryOffset == 0x55555555, "wrong offset %x\n", next->NextEntryOffset );
|
||||
|
||||
data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ),
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
|
||||
"wrong info %lx\n", U(io).Information );
|
||||
ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
|
||||
data_size = ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7) +
|
||||
offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] );
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size );
|
||||
ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"wrong offset %x\n", fbdi->NextEntryOffset );
|
||||
ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength );
|
||||
ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
|
||||
next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
|
||||
ok( next->NextEntryOffset == 0, "wrong offset %x\n", next->NextEntryOffset );
|
||||
ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength );
|
||||
filename = next->FileName;
|
||||
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
data_size = ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7) +
|
||||
offsetof( FILE_NAMES_INFORMATION, FileName[2] );
|
||||
memset( data, 0x55, data_size );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
U(io).Information = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileNamesInformation, FALSE, NULL, TRUE );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
|
||||
ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size );
|
||||
names = (FILE_NAMES_INFORMATION *)data;
|
||||
ok( names->NextEntryOffset == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7),
|
||||
"wrong offset %x\n", names->NextEntryOffset );
|
||||
ok( names->FileNameLength == sizeof(WCHAR), "wrong length %x\n", names->FileNameLength );
|
||||
ok( names->FileName[0] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR)));
|
||||
names = (FILE_NAMES_INFORMATION *)(data + names->NextEntryOffset);
|
||||
ok( names->NextEntryOffset == 0, "wrong offset %x\n", names->NextEntryOffset );
|
||||
ok( names->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", names->FileNameLength );
|
||||
filename = names->FileName;
|
||||
ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n",
|
||||
wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR)));
|
||||
|
||||
pNtClose(dirh);
|
||||
|
||||
/* create new handle to change mask */
|
||||
status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE);
|
||||
ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA);
|
||||
|
||||
pRtlInitUnicodeString( &mask, dummyW );
|
||||
U(io).Status = 0xdeadbeef;
|
||||
data_size = sizeof(data);
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, &mask, TRUE);
|
||||
ok(status == STATUS_NO_SUCH_FILE, "wrong status %x\n", status);
|
||||
ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status);
|
||||
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, NULL, FALSE);
|
||||
ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status);
|
||||
ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n", U(io).Status);
|
||||
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, NULL, TRUE);
|
||||
ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status);
|
||||
ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n", U(io).Status);
|
||||
|
||||
pNtClose(dirh);
|
||||
|
||||
U(io).Status = 0xdeadbeef;
|
||||
status = pNtQueryDirectoryFile( (HANDLE)0xbeef, 0, NULL, NULL, &io, data, data_size,
|
||||
FileBothDirectoryInformation, TRUE, NULL, TRUE );
|
||||
ok(status == STATUS_INVALID_HANDLE, "wrong status %x\n", status);
|
||||
ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status);
|
||||
|
||||
done:
|
||||
tear_down_attribute_test(testdirA);
|
||||
test_directory_sort( testdirW );
|
||||
tear_down_attribute_test( testdirW );
|
||||
pRtlFreeUnicodeString(&ntdirname);
|
||||
}
|
||||
|
||||
@@ -403,6 +861,8 @@ static void test_redirection(void)
|
||||
ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status );
|
||||
status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)1 );
|
||||
ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status );
|
||||
status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)0xDEADBEEF );
|
||||
ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status );
|
||||
|
||||
status = pRtlWow64EnableFsRedirection( FALSE );
|
||||
ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status );
|
||||
@@ -415,6 +875,7 @@ static void test_redirection(void)
|
||||
|
||||
START_TEST(directory)
|
||||
{
|
||||
WCHAR sysdir[MAX_PATH];
|
||||
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
|
||||
if (!hntdll)
|
||||
{
|
||||
@@ -425,14 +886,19 @@ START_TEST(directory)
|
||||
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
|
||||
pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile");
|
||||
pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile");
|
||||
pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile");
|
||||
pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile");
|
||||
pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz");
|
||||
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U");
|
||||
pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
|
||||
pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
|
||||
pRtlCompareUnicodeString = (void *)GetProcAddress(hntdll, "RtlCompareUnicodeString");
|
||||
pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll,"RtlMultiByteToUnicodeN");
|
||||
pRtlWow64EnableFsRedirection = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirection");
|
||||
pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirectionEx");
|
||||
|
||||
GetSystemDirectoryW( sysdir, MAX_PATH );
|
||||
test_directory_sort( sysdir );
|
||||
test_NtQueryDirectoryFile();
|
||||
test_NtQueryDirectoryFile_case();
|
||||
test_redirection();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -94,6 +94,7 @@ static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
|
||||
static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE hFile, PIO_STATUS_BLOCK io_status);
|
||||
static NTSTATUS (WINAPI *pNtCancelIoFileEx)(HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status);
|
||||
static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
|
||||
static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code, PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size);
|
||||
|
||||
static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG);
|
||||
static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
|
||||
@@ -106,6 +107,7 @@ static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PV
|
||||
PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
|
||||
static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS);
|
||||
static NTSTATUS (WINAPI *pNtQueryFullAttributesFile)(const OBJECT_ATTRIBUTES*, FILE_NETWORK_OPEN_INFORMATION*);
|
||||
static NTSTATUS (WINAPI *pNtFlushBuffersFile)(HANDLE, IO_STATUS_BLOCK*);
|
||||
static NTSTATUS (WINAPI *pNtQueryEaFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,BOOLEAN,PVOID,ULONG,PULONG,BOOLEAN);
|
||||
|
||||
static inline BOOL is_signaled( HANDLE obj )
|
||||
@@ -113,31 +115,8 @@ static inline BOOL is_signaled( HANDLE obj )
|
||||
return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
static const char* debugstr_longlong(ULONGLONG ll)
|
||||
{
|
||||
static char str[17];
|
||||
if (sizeof(ll) > sizeof(unsigned long) && ll >> 32)
|
||||
sprintf(str, "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll);
|
||||
else
|
||||
sprintf(str, "%lx", (unsigned long)ll);
|
||||
return str;
|
||||
}
|
||||
|
||||
#define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
|
||||
#define TEST_BUF_LEN 3
|
||||
|
||||
static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size )
|
||||
{
|
||||
*read = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT,
|
||||
1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
|
||||
ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
*write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HANDLE create_temp_file( ULONG flags )
|
||||
{
|
||||
char path[MAX_PATH], buffer[MAX_PATH];
|
||||
@@ -198,18 +177,22 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
|
||||
|
||||
static void create_file_test(void)
|
||||
{
|
||||
static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0};
|
||||
static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t',
|
||||
'\\','f','a','i','l','i','n','g',0};
|
||||
static const WCHAR systemrootExplorerW[] = {'\\','S','y','s','t','e','m','R','o','o','t',
|
||||
'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
|
||||
static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0};
|
||||
static const WCHAR pipeInvalidNameW[] = {'a','|','b',0};
|
||||
static const WCHAR pathInvalidNtW[] = {'\\','\\','?','\\',0};
|
||||
static const WCHAR pathInvalidNt2W[] = {'\\','?','?','\\',0};
|
||||
static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
|
||||
static const char testdata[] = "Hello World";
|
||||
static const WCHAR sepW[] = {'\\',0};
|
||||
FILE_NETWORK_OPEN_INFORMATION info;
|
||||
NTSTATUS status;
|
||||
HANDLE dir, file;
|
||||
WCHAR path[MAX_PATH];
|
||||
WCHAR path[MAX_PATH], temp[MAX_PATH];
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
IO_STATUS_BLOCK io;
|
||||
UNICODE_STRING nameW;
|
||||
@@ -389,6 +372,25 @@ static void create_file_test(void)
|
||||
status = pNtQueryFullAttributesFile( &attr, &info );
|
||||
ok( status == STATUS_OBJECT_NAME_INVALID,
|
||||
"query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
|
||||
|
||||
GetWindowsDirectoryW( path, MAX_PATH );
|
||||
path[2] = 0;
|
||||
ok( QueryDosDeviceW( path, temp, MAX_PATH ),
|
||||
"QueryDosDeviceW failed with error %u\n", GetLastError() );
|
||||
lstrcatW( temp, sepW );
|
||||
lstrcatW( temp, path+3 );
|
||||
lstrcatW( temp, sepW );
|
||||
lstrcatW( temp, notepadW );
|
||||
|
||||
pRtlInitUnicodeString( &nameW, temp );
|
||||
status = pNtQueryFullAttributesFile( &attr, &info );
|
||||
ok( status == STATUS_SUCCESS,
|
||||
"query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
|
||||
|
||||
pRtlInitUnicodeString( &nameW, systemrootExplorerW );
|
||||
status = pNtQueryFullAttributesFile( &attr, &info );
|
||||
ok( status == STATUS_SUCCESS,
|
||||
"query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
|
||||
}
|
||||
|
||||
static void open_file_test(void)
|
||||
@@ -660,268 +662,14 @@ static void delete_file_test(void)
|
||||
static void read_file_test(void)
|
||||
{
|
||||
const char text[] = "foobar";
|
||||
HANDLE handle, read, write;
|
||||
HANDLE handle;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK iosb, iosb2;
|
||||
DWORD written;
|
||||
int apc_count = 0;
|
||||
char buffer[128];
|
||||
LARGE_INTEGER offset;
|
||||
HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
BOOL ret;
|
||||
|
||||
buffer[0] = 1;
|
||||
|
||||
if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
|
||||
|
||||
/* try read with no data */
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ok( is_signaled( read ), "read handle is not signaled\n" );
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
/* iosb updated here by async i/o */
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
apc_count = 0;
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* with no event, the pipe handle itself gets signaled */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
/* iosb updated here by async i/o */
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( read ), "read handle is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
apc_count = 0;
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* now read with data ready */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ResetEvent( event );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* try read with no data */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
/* partial read is good enough */
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
|
||||
/* read from disconnected pipe */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
CloseHandle( write );
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
CloseHandle( read );
|
||||
|
||||
/* read from closed handle */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
SetEvent( event );
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on invalid handle */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
|
||||
/* disconnect while async read is in progress */
|
||||
if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
CloseHandle( write );
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
CloseHandle( read );
|
||||
|
||||
if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
|
||||
ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||
ok(ret, "Failed to duplicate handle: %d\n", GetLastError());
|
||||
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
/* Cancel by other handle */
|
||||
status = pNtCancelIoFile( read, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status);
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
/* Close queued handle */
|
||||
CloseHandle( read );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
status = pNtCancelIoFile( read, &iosb2 );
|
||||
ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
|
||||
status = pNtCancelIoFile( handle, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
CloseHandle( handle );
|
||||
CloseHandle( write );
|
||||
|
||||
if (pNtCancelIoFileEx)
|
||||
{
|
||||
/* Basic Cancel Ex */
|
||||
if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
|
||||
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
|
||||
/* Duplicate iosb */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 2, "apc was not called\n" );
|
||||
|
||||
CloseHandle( read );
|
||||
CloseHandle( write );
|
||||
}
|
||||
|
||||
/* now try a real file */
|
||||
if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return;
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
@@ -1297,7 +1045,7 @@ static void test_iocp_fileio(HANDLE h)
|
||||
ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
|
||||
ok( ioSb.Information == 0, "Invalid ioSb.Information: %ld\n", ioSb.Information );
|
||||
/* wine sends wrong status here */
|
||||
todo_wine ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
|
||||
ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
|
||||
ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
|
||||
}
|
||||
}
|
||||
@@ -1315,6 +1063,7 @@ static void test_iocp_fileio(HANDLE h)
|
||||
{
|
||||
OVERLAPPED o = {0,};
|
||||
BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
|
||||
int apc_count = 0;
|
||||
DWORD read;
|
||||
long count;
|
||||
|
||||
@@ -1343,6 +1092,58 @@ static void test_iocp_fileio(HANDLE h)
|
||||
}
|
||||
count = get_pending_msgs(h);
|
||||
ok( !count, "Unexpected msg count: %ld\n", count );
|
||||
|
||||
/* using APCs on handle with associated completion port is not allowed */
|
||||
res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf, sizeof(recv_buf), NULL, NULL );
|
||||
ok(res == STATUS_INVALID_PARAMETER, "NtReadFile returned %x\n", res);
|
||||
}
|
||||
|
||||
CloseHandle( hPipeSrv );
|
||||
CloseHandle( hPipeClt );
|
||||
|
||||
/* test associating a completion port with a handle after an async using APC is queued */
|
||||
hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL );
|
||||
ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" );
|
||||
if (hPipeSrv == INVALID_HANDLE_VALUE )
|
||||
return;
|
||||
hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
|
||||
ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" );
|
||||
if (hPipeClt != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
|
||||
int apc_count = 0;
|
||||
DWORD read;
|
||||
long count;
|
||||
|
||||
memset( send_buf, 0, TEST_BUF_LEN );
|
||||
memset( recv_buf, 0xde, TEST_BUF_LEN );
|
||||
count = get_pending_msgs(h);
|
||||
ok( !count, "Unexpected msg count: %ld\n", count );
|
||||
|
||||
res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf, sizeof(recv_buf), NULL, NULL );
|
||||
ok(res == STATUS_PENDING, "NtReadFile returned %x\n", res);
|
||||
|
||||
U(iosb).Status = 0xdeadbeef;
|
||||
res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation );
|
||||
ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res );
|
||||
ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n", U(iosb).Status );
|
||||
count = get_pending_msgs(h);
|
||||
ok( !count, "Unexpected msg count: %ld\n", count );
|
||||
|
||||
WriteFile( hPipeClt, send_buf, TEST_BUF_LEN, &read, NULL );
|
||||
|
||||
ok(!apc_count, "apc_count = %u\n", apc_count);
|
||||
count = get_pending_msgs(h);
|
||||
ok( !count, "Unexpected msg count: %ld\n", count );
|
||||
|
||||
SleepEx(1, TRUE); /* alertable sleep */
|
||||
ok(apc_count == 1, "apc was not called\n");
|
||||
count = get_pending_msgs(h);
|
||||
ok( !count, "Unexpected msg count: %ld\n", count );
|
||||
|
||||
/* using APCs on handle with associated completion port is not allowed */
|
||||
res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf, sizeof(recv_buf), NULL, NULL );
|
||||
ok(res == STATUS_INVALID_PARAMETER, "NtReadFile returned %x\n", res);
|
||||
}
|
||||
|
||||
CloseHandle( hPipeSrv );
|
||||
@@ -1371,10 +1172,10 @@ static void test_file_full_size_information(void)
|
||||
/* Test for FileFsSizeInformation */
|
||||
ok(fsi.TotalAllocationUnits.QuadPart > 0,
|
||||
"[fsi] TotalAllocationUnits expected positive, got 0x%s\n",
|
||||
debugstr_longlong(fsi.TotalAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart));
|
||||
ok(fsi.AvailableAllocationUnits.QuadPart > 0,
|
||||
"[fsi] AvailableAllocationUnits expected positive, got 0x%s\n",
|
||||
debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart));
|
||||
|
||||
/* Assume file system is NTFS */
|
||||
ok(fsi.BytesPerSector == 512, "[fsi] BytesPerSector expected 512, got %d\n",fsi.BytesPerSector);
|
||||
@@ -1382,21 +1183,21 @@ static void test_file_full_size_information(void)
|
||||
|
||||
ok(ffsi.TotalAllocationUnits.QuadPart > 0,
|
||||
"[ffsi] TotalAllocationUnits expected positive, got negative value 0x%s\n",
|
||||
debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
|
||||
ok(ffsi.CallerAvailableAllocationUnits.QuadPart > 0,
|
||||
"[ffsi] CallerAvailableAllocationUnits expected positive, got negative value 0x%s\n",
|
||||
debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
|
||||
ok(ffsi.ActualAvailableAllocationUnits.QuadPart > 0,
|
||||
"[ffsi] ActualAvailableAllocationUnits expected positive, got negative value 0x%s\n",
|
||||
debugstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart));
|
||||
ok(ffsi.TotalAllocationUnits.QuadPart == fsi.TotalAllocationUnits.QuadPart,
|
||||
"[ffsi] TotalAllocationUnits error fsi:0x%s, ffsi:0x%s\n",
|
||||
debugstr_longlong(fsi.TotalAllocationUnits.QuadPart),
|
||||
debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart),
|
||||
wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
|
||||
ok(ffsi.CallerAvailableAllocationUnits.QuadPart == fsi.AvailableAllocationUnits.QuadPart,
|
||||
"[ffsi] CallerAvailableAllocationUnits error fsi:0x%s, ffsi: 0x%s\n",
|
||||
debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart),
|
||||
debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
|
||||
wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart),
|
||||
wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
|
||||
|
||||
/* Assume file system is NTFS */
|
||||
ok(ffsi.BytesPerSector == 512, "[ffsi] BytesPerSector expected 512, got %d\n",ffsi.BytesPerSector);
|
||||
@@ -1592,7 +1393,7 @@ static void test_file_rename_information(void)
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
|
||||
ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
@@ -1762,7 +1563,7 @@ static void test_file_rename_information(void)
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
|
||||
ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
@@ -2168,7 +1969,7 @@ static void test_file_rename_information(void)
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
|
||||
ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
@@ -2181,6 +1982,7 @@ static void test_file_rename_information(void)
|
||||
|
||||
static void test_file_link_information(void)
|
||||
{
|
||||
static const WCHAR pipeW[] = {'\\','\\','.','\\','p','i','p','e','\\','w','i','n','e','_','t','e','s','t',0};
|
||||
static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0};
|
||||
static const WCHAR fooW[] = {'f','o','o',0};
|
||||
WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p;
|
||||
@@ -2224,7 +2026,7 @@ static void test_file_link_information(void)
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
|
||||
ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
@@ -2394,7 +2196,7 @@ static void test_file_link_information(void)
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
|
||||
ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
@@ -2797,12 +2599,36 @@ static void test_file_link_information(void)
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
|
||||
ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
CloseHandle( handle );
|
||||
CloseHandle( handle2 );
|
||||
|
||||
handle = CreateEventA( NULL, FALSE, FALSE, "wine_test_event" );
|
||||
ok( !!handle, "Failed to create event: %u\n", GetLastError());
|
||||
|
||||
fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_OBJECT_TYPE_MISMATCH, "res expected STATUS_OBJECT_TYPE_MISMATCH, got %x\n", res );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
CloseHandle( handle );
|
||||
|
||||
handle = CreateNamedPipeW( pipeW, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 10, 512, 512, 0, NULL);
|
||||
ok( handle != INVALID_HANDLE_VALUE, "Failed to create named pipe: %u\n", GetLastError());
|
||||
|
||||
fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) );
|
||||
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );
|
||||
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
|
||||
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
|
||||
ok( !lstrcmpiW(fni->FileName, pipeW + 8), "FileName expected %s, got %s\n",
|
||||
wine_dbgstr_w(pipeW + 8), wine_dbgstr_w(fni->FileName) );
|
||||
HeapFree( GetProcessHeap(), 0, fni );
|
||||
|
||||
CloseHandle( handle );
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, fli );
|
||||
delete_object( oldpath );
|
||||
delete_object( newpath );
|
||||
@@ -3349,6 +3175,213 @@ static void test_file_all_name_information(void)
|
||||
HeapFree( GetProcessHeap(), 0, file_name );
|
||||
}
|
||||
|
||||
static void test_file_completion_information(void)
|
||||
{
|
||||
static const char buf[] = "testdata";
|
||||
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
|
||||
OVERLAPPED ov, *pov;
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
DWORD num_bytes;
|
||||
HANDLE port, h;
|
||||
ULONG_PTR key;
|
||||
BOOL ret;
|
||||
int i;
|
||||
|
||||
if (!(h = create_temp_file(0))) return;
|
||||
|
||||
status = pNtSetInformationFile(h, &io, &info, sizeof(info) - 1, FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_INFO_CLASS /* XP */,
|
||||
"expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
|
||||
if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED)
|
||||
{
|
||||
win_skip("FileIoCompletionNotificationInformation class not supported\n");
|
||||
CloseHandle(h);
|
||||
return;
|
||||
}
|
||||
|
||||
info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
|
||||
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %08x\n", status);
|
||||
|
||||
CloseHandle(h);
|
||||
if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return;
|
||||
|
||||
info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE;
|
||||
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
info.Flags = FILE_SKIP_SET_USER_EVENT_ON_FAST_IO;
|
||||
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
CloseHandle(h);
|
||||
if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return;
|
||||
|
||||
info.Flags = ~0U;
|
||||
status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok(!(info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS), "got %08x\n", info.Flags);
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
port = CreateIoCompletionPort(h, NULL, 0xdeadbeef, 0);
|
||||
ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov);
|
||||
if (ret || GetLastError() != ERROR_IO_PENDING) break;
|
||||
ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE);
|
||||
ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError());
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
|
||||
ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
|
||||
ret = FALSE;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
|
||||
|
||||
key = 0;
|
||||
pov = NULL;
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
|
||||
ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
|
||||
ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key);
|
||||
ok(pov == &ov, "expected %p, got %p\n", &ov, pov);
|
||||
}
|
||||
else
|
||||
win_skip("WriteFile never returned TRUE\n");
|
||||
|
||||
info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
|
||||
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
info.Flags = 0;
|
||||
status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov);
|
||||
if (ret || GetLastError() != ERROR_IO_PENDING) break;
|
||||
ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE);
|
||||
ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError());
|
||||
ret = FALSE;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
|
||||
|
||||
pov = (void *)0xdeadbeef;
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 500);
|
||||
ok(!ret, "GetQueuedCompletionStatus succeeded\n");
|
||||
ok(pov == NULL, "expected NULL, got %p\n", pov);
|
||||
}
|
||||
else
|
||||
win_skip("WriteFile never returned TRUE\n");
|
||||
|
||||
info.Flags = 0;
|
||||
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
info.Flags = 0;
|
||||
status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov);
|
||||
if (ret || GetLastError() != ERROR_IO_PENDING) break;
|
||||
ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE);
|
||||
ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError());
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
|
||||
ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
|
||||
ret = FALSE;
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
|
||||
|
||||
pov = (void *)0xdeadbeef;
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
|
||||
ok(!ret, "GetQueuedCompletionStatus succeeded\n");
|
||||
ok(pov == NULL, "expected NULL, got %p\n", pov);
|
||||
}
|
||||
else
|
||||
win_skip("WriteFile never returned TRUE\n");
|
||||
|
||||
CloseHandle(ov.hEvent);
|
||||
CloseHandle(port);
|
||||
CloseHandle(h);
|
||||
}
|
||||
|
||||
static void test_file_id_information(void)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
FILE_ID_INFORMATION fid;
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
DWORD *dwords;
|
||||
HANDLE h;
|
||||
BOOL ret;
|
||||
|
||||
if (!(h = create_temp_file(0))) return;
|
||||
|
||||
memset( &fid, 0x11, sizeof(fid) );
|
||||
status = pNtQueryInformationFile( h, &io, &fid, sizeof(fid), FileIdInformation );
|
||||
if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
|
||||
{
|
||||
win_skip( "FileIdInformation not supported\n" );
|
||||
CloseHandle( h );
|
||||
return;
|
||||
}
|
||||
|
||||
memset( &info, 0x22, sizeof(info) );
|
||||
ret = GetFileInformationByHandle( h, &info );
|
||||
ok( ret, "GetFileInformationByHandle failed\n" );
|
||||
|
||||
dwords = (DWORD *)&fid.VolumeSerialNumber;
|
||||
ok( dwords[0] == info.dwVolumeSerialNumber, "expected %08x, got %08x\n",
|
||||
info.dwVolumeSerialNumber, dwords[0] );
|
||||
ok( dwords[1] != 0x11111111, "expected != 0x11111111\n" );
|
||||
|
||||
dwords = (DWORD *)&fid.FileId;
|
||||
ok( dwords[0] == info.nFileIndexLow, "expected %08x, got %08x\n", info.nFileIndexLow, dwords[0] );
|
||||
ok( dwords[1] == info.nFileIndexHigh, "expected %08x, got %08x\n", info.nFileIndexHigh, dwords[1] );
|
||||
ok( dwords[2] == 0, "expected 0, got %08x\n", dwords[2] );
|
||||
ok( dwords[3] == 0, "expected 0, got %08x\n", dwords[3] );
|
||||
|
||||
CloseHandle( h );
|
||||
}
|
||||
|
||||
static void test_file_access_information(void)
|
||||
{
|
||||
FILE_ACCESS_INFORMATION info;
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
HANDLE h;
|
||||
|
||||
if (!(h = create_temp_file(0))) return;
|
||||
|
||||
status = pNtQueryInformationFile( h, &io, &info, sizeof(info) - 1, FileAccessInformation );
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status );
|
||||
|
||||
status = pNtQueryInformationFile( (HANDLE)0xdeadbeef, &io, &info, sizeof(info), FileAccessInformation );
|
||||
ok( status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08x\n", status );
|
||||
|
||||
memset(&info, 0x11, sizeof(info));
|
||||
status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileAccessInformation );
|
||||
ok( status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status );
|
||||
ok( info.AccessFlags == 0x13019f, "got %08x\n", info.AccessFlags );
|
||||
|
||||
CloseHandle( h );
|
||||
}
|
||||
|
||||
static void test_query_volume_information_file(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
@@ -3616,13 +3649,15 @@ static void test_read_write(void)
|
||||
{
|
||||
static const char contents[14] = "1234567890abcd";
|
||||
char buf[256];
|
||||
HANDLE hfile;
|
||||
HANDLE hfile, event;
|
||||
OVERLAPPED ovl;
|
||||
IO_STATUS_BLOCK iob;
|
||||
DWORD ret, bytes, status, off;
|
||||
LARGE_INTEGER offset;
|
||||
LONG i;
|
||||
|
||||
event = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
offset.QuadPart = 0;
|
||||
@@ -3631,6 +3666,22 @@ static void test_read_write(void)
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
offset.QuadPart = 0;
|
||||
status = pNtReadFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, NULL, sizeof(buf), &offset, NULL);
|
||||
ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, "expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status);
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
offset.QuadPart = 0;
|
||||
status = pNtWriteFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, buf, sizeof(buf), &offset, NULL);
|
||||
ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE, "expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status);
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
offset.QuadPart = 0;
|
||||
@@ -3649,6 +3700,15 @@ static void test_read_write(void)
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
SetEvent(event);
|
||||
status = pNtWriteFile(hfile, event, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL);
|
||||
ok(status == STATUS_INVALID_USER_BUFFER, "expected STATUS_INVALID_USER_BUFFER, got %#x\n", status);
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
ok(!is_signaled(event), "event is not signaled\n");
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
status = pNtReadFile(hfile, 0, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL);
|
||||
@@ -3656,6 +3716,24 @@ static void test_read_write(void)
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
SetEvent(event);
|
||||
status = pNtReadFile(hfile, event, NULL, NULL, &iob, NULL, sizeof(contents), NULL, NULL);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status);
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
ok(is_signaled(event), "event is not signaled\n");
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
SetEvent(event);
|
||||
status = pNtReadFile(hfile, event, NULL, NULL, &iob, (void*)0xdeadbeef, sizeof(contents), NULL, NULL);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status);
|
||||
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
|
||||
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
|
||||
ok(is_signaled(event), "event is not signaled\n");
|
||||
|
||||
U(iob).Status = -1;
|
||||
iob.Information = -1;
|
||||
status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, 7, NULL, NULL);
|
||||
@@ -4321,9 +4399,80 @@ static void test_read_write(void)
|
||||
off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT);
|
||||
ok(off == 0, "expected 0, got %u\n", off);
|
||||
|
||||
CloseHandle(event);
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
|
||||
static void test_ioctl(void)
|
||||
{
|
||||
HANDLE event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
IO_STATUS_BLOCK iosb;
|
||||
HANDLE file;
|
||||
NTSTATUS status;
|
||||
|
||||
file = create_temp_file(FILE_FLAG_OVERLAPPED);
|
||||
ok(file != INVALID_HANDLE_VALUE, "could not create temp file\n");
|
||||
|
||||
SetEvent(event);
|
||||
status = pNtFsControlFile(file, event, NULL, NULL, &iosb, 0xdeadbeef, 0, 0, 0, 0);
|
||||
todo_wine
|
||||
ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtFsControlFile returned %x\n", status);
|
||||
ok(!is_signaled(event), "event is signaled\n");
|
||||
|
||||
status = pNtFsControlFile(file, (HANDLE)0xdeadbeef, NULL, NULL, &iosb, 0xdeadbeef, 0, 0, 0, 0);
|
||||
ok(status == STATUS_INVALID_HANDLE, "NtFsControlFile returned %x\n", status);
|
||||
|
||||
CloseHandle(event);
|
||||
CloseHandle(file);
|
||||
}
|
||||
|
||||
static void test_flush_buffers_file(void)
|
||||
{
|
||||
char path[MAX_PATH], buffer[MAX_PATH];
|
||||
HANDLE hfile, hfileread;
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK io_status_block;
|
||||
|
||||
GetTempPathA(MAX_PATH, path);
|
||||
GetTempFileNameA(path, "foo", 0, buffer);
|
||||
hfile = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, 0);
|
||||
ok(hfile != INVALID_HANDLE_VALUE, "failed to create temp file.\n" );
|
||||
|
||||
hfileread = CreateFileA(buffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, 0, NULL);
|
||||
ok(hfileread != INVALID_HANDLE_VALUE, "could not open temp file, error %d.\n", GetLastError());
|
||||
|
||||
status = pNtFlushBuffersFile(hfile, NULL);
|
||||
todo_wine
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x.\n", status);
|
||||
|
||||
status = pNtFlushBuffersFile(hfile, (IO_STATUS_BLOCK *)0xdeadbeaf);
|
||||
todo_wine
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x.\n", status);
|
||||
|
||||
status = pNtFlushBuffersFile(hfile, &io_status_block);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x.\n", status);
|
||||
|
||||
status = pNtFlushBuffersFile(hfileread, &io_status_block);
|
||||
ok(status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got %#x.\n", status);
|
||||
|
||||
status = pNtFlushBuffersFile(NULL, &io_status_block);
|
||||
ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %#x.\n", status);
|
||||
|
||||
CloseHandle(hfileread);
|
||||
CloseHandle(hfile);
|
||||
hfile = CreateFileA(buffer, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, 0, NULL);
|
||||
ok(hfile != INVALID_HANDLE_VALUE, "could not open temp file, error %d.\n", GetLastError());
|
||||
|
||||
status = pNtFlushBuffersFile(hfile, &io_status_block);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x.\n", status);
|
||||
|
||||
CloseHandle(hfile);
|
||||
DeleteFileA(buffer);
|
||||
}
|
||||
|
||||
static void test_query_ea(void)
|
||||
{
|
||||
#define EA_BUFFER_SIZE 4097
|
||||
@@ -4601,6 +4750,7 @@ START_TEST(file)
|
||||
pNtCancelIoFile = (void *)GetProcAddress(hntdll, "NtCancelIoFile");
|
||||
pNtCancelIoFileEx = (void *)GetProcAddress(hntdll, "NtCancelIoFileEx");
|
||||
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
|
||||
pNtFsControlFile = (void *)GetProcAddress(hntdll, "NtFsControlFile");
|
||||
pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion");
|
||||
pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion");
|
||||
pNtQueryIoCompletion = (void *)GetProcAddress(hntdll, "NtQueryIoCompletion");
|
||||
@@ -4611,6 +4761,7 @@ START_TEST(file)
|
||||
pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile");
|
||||
pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll, "NtQueryVolumeInformationFile");
|
||||
pNtQueryFullAttributesFile = (void *)GetProcAddress(hntdll, "NtQueryFullAttributesFile");
|
||||
pNtFlushBuffersFile = (void *)GetProcAddress(hntdll, "NtFlushBuffersFile");
|
||||
pNtQueryEaFile = (void *)GetProcAddress(hntdll, "NtQueryEaFile");
|
||||
|
||||
test_read_write();
|
||||
@@ -4632,8 +4783,13 @@ START_TEST(file)
|
||||
test_file_rename_information();
|
||||
test_file_link_information();
|
||||
test_file_disposition_information();
|
||||
test_file_completion_information();
|
||||
test_file_id_information();
|
||||
test_file_access_information();
|
||||
test_query_volume_information_file();
|
||||
test_query_attribute_information_file();
|
||||
test_ioctl();
|
||||
test_flush_buffers_file();
|
||||
test_query_ea();
|
||||
test_junction_points();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include <winnls.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static NTSTATUS (WINAPI * pRtlDowncaseUnicodeString)(UNICODE_STRING *, const UNICODE_STRING *, BOOLEAN);
|
||||
static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
|
||||
static NTSTATUS (WINAPI * pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*, ULONG, void*, ULONG, ULONG*);
|
||||
static NTSTATUS (WINAPI * pNtPowerInformation)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG);
|
||||
static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
|
||||
static NTSTATUS (WINAPI * pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG);
|
||||
@@ -36,6 +38,7 @@ static NTSTATUS (WINAPI * pNtUnmapViewOfSection)(HANDLE,PVOID);
|
||||
static NTSTATUS (WINAPI * pNtClose)(HANDLE);
|
||||
static ULONG (WINAPI * pNtGetCurrentProcessorNumber)(void);
|
||||
static BOOL (WINAPI * pIsWow64Process)(HANDLE, PBOOL);
|
||||
static BOOL (WINAPI * pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
|
||||
|
||||
static BOOL is_wow64;
|
||||
|
||||
@@ -56,12 +59,15 @@ static BOOL InitFunctionPtrs(void)
|
||||
{
|
||||
/* All needed functions are NT based, so using GetModuleHandle is a good check */
|
||||
HMODULE hntdll = GetModuleHandleA("ntdll");
|
||||
HMODULE hkernel32 = GetModuleHandleA("kernel32");
|
||||
|
||||
if (!hntdll)
|
||||
{
|
||||
win_skip("Not running on NT\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NTDLL_GET_PROC(RtlDowncaseUnicodeString);
|
||||
NTDLL_GET_PROC(NtQuerySystemInformation);
|
||||
NTDLL_GET_PROC(NtPowerInformation);
|
||||
NTDLL_GET_PROC(NtQueryInformationProcess);
|
||||
@@ -78,8 +84,16 @@ static BOOL InitFunctionPtrs(void)
|
||||
/* not present before XP */
|
||||
pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll, "NtGetCurrentProcessorNumber");
|
||||
|
||||
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
|
||||
pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process");
|
||||
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
|
||||
|
||||
/* starting with Win7 */
|
||||
pNtQuerySystemInformationEx = (void *) GetProcAddress(hntdll, "NtQuerySystemInformationEx");
|
||||
if (!pNtQuerySystemInformationEx)
|
||||
win_skip("NtQuerySystemInformationEx() is not supported, some tests will be skipped.\n");
|
||||
|
||||
pGetLogicalProcessorInformationEx = (void *) GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -288,7 +302,7 @@ static void test_query_process(void)
|
||||
/* test ReturnLength */
|
||||
ReturnLength = 0;
|
||||
status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ReturnLength);
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_LENGTH_MISMATCH got %08x\n", status);
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH got %08x\n", status);
|
||||
ok( ReturnLength > 0 || broken(ReturnLength == 0) /* NT4, Win2K */,
|
||||
"Expected a ReturnLength to show the needed length\n");
|
||||
|
||||
@@ -474,13 +488,15 @@ static void test_query_module(void)
|
||||
static void test_query_handle(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG ReturnLength;
|
||||
ULONG ExpectedLength, ReturnLength;
|
||||
ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION);
|
||||
SYSTEM_HANDLE_INFORMATION* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength);
|
||||
HANDLE event_handle;
|
||||
HANDLE EventHandle;
|
||||
BOOL found;
|
||||
INT i;
|
||||
|
||||
event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ok( event_handle != NULL, "CreateEventA failed %u\n", GetLastError() );
|
||||
EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() );
|
||||
|
||||
/* Request the needed length : a SystemInformationLength greater than one struct sets ReturnLength */
|
||||
ReturnLength = 0xdeadbeef;
|
||||
@@ -490,34 +506,116 @@ static void test_query_handle(void)
|
||||
|
||||
SystemInformationLength = ReturnLength;
|
||||
shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength);
|
||||
memset(shi, 0x55, SystemInformationLength);
|
||||
|
||||
ReturnLength = 0xdeadbeef;
|
||||
status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
if (status != STATUS_INFO_LENGTH_MISMATCH) /* vista */
|
||||
while (status == STATUS_INFO_LENGTH_MISMATCH) /* Vista / 2008 */
|
||||
{
|
||||
ULONG ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]);
|
||||
unsigned int i;
|
||||
BOOL found = FALSE;
|
||||
|
||||
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" );
|
||||
SystemInformationLength *= 2;
|
||||
shi = HeapReAlloc(GetProcessHeap(), 0, shi, SystemInformationLength);
|
||||
memset(shi, 0x55, SystemInformationLength);
|
||||
status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
}
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status );
|
||||
ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]);
|
||||
ok( ReturnLength == ExpectedLength || broken(ReturnLength == ExpectedLength - sizeof(DWORD)), /* Vista / 2008 */
|
||||
"Expected length %u, got %u\n", ExpectedLength, ReturnLength );
|
||||
ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", shi->Count );
|
||||
ok( shi->Handle[1].HandleValue != 0x5555 || broken( shi->Handle[1].HandleValue == 0x5555 ), /* Vista / 2008 */
|
||||
"Uninitialized second handle\n" );
|
||||
if (shi->Handle[1].HandleValue == 0x5555)
|
||||
{
|
||||
win_skip("Skipping broken SYSTEM_HANDLE_INFORMATION\n");
|
||||
CloseHandle(EventHandle);
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0, found = FALSE; i < shi->Count && !found; i++)
|
||||
found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) &&
|
||||
((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
|
||||
ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() );
|
||||
|
||||
if (!found)
|
||||
for (i = 0; i < shi->Count; i++)
|
||||
trace( "%d: handle %x pid %x\n", i, shi->Handle[i].HandleValue, shi->Handle[i].OwnerPid );
|
||||
|
||||
CloseHandle(EventHandle);
|
||||
|
||||
ReturnLength = 0xdeadbeef;
|
||||
status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
while (status == STATUS_INFO_LENGTH_MISMATCH) /* Vista / 2008 */
|
||||
{
|
||||
SystemInformationLength *= 2;
|
||||
shi = HeapReAlloc(GetProcessHeap(), 0, shi, SystemInformationLength);
|
||||
status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
}
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status );
|
||||
for (i = 0, found = FALSE; i < shi->Count && !found; i++)
|
||||
found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) &&
|
||||
((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
|
||||
ok( !found, "Unexpectedly found event handle in handle list\n" );
|
||||
|
||||
status = pNtQuerySystemInformation(SystemHandleInformation, NULL, SystemInformationLength, &ReturnLength);
|
||||
ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status );
|
||||
|
||||
CloseHandle(event_handle);
|
||||
done:
|
||||
HeapFree( GetProcessHeap(), 0, shi);
|
||||
}
|
||||
|
||||
static void test_query_handle_ex(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG ExpectedLength, ReturnLength;
|
||||
ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION_EX);
|
||||
SYSTEM_HANDLE_INFORMATION_EX* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength);
|
||||
HANDLE EventHandle;
|
||||
BOOL found;
|
||||
INT i;
|
||||
|
||||
EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() );
|
||||
|
||||
ReturnLength = 0xdeadbeef;
|
||||
status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
|
||||
ok( ReturnLength != 0xdeadbeef, "Expected valid ReturnLength\n" );
|
||||
|
||||
SystemInformationLength = ReturnLength;
|
||||
shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength);
|
||||
memset(shi, 0x55, SystemInformationLength);
|
||||
|
||||
ReturnLength = 0xdeadbeef;
|
||||
status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status );
|
||||
ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle[shi->Count]);
|
||||
ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n", ExpectedLength, ReturnLength );
|
||||
ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", (DWORD)shi->Count );
|
||||
|
||||
for (i = 0, found = FALSE; i < shi->Count && !found; i++)
|
||||
found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) &&
|
||||
((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
|
||||
ok( found, "Expected to find event handle %p (pid %x) in handle list\n", EventHandle, GetCurrentProcessId() );
|
||||
|
||||
if (!found)
|
||||
{
|
||||
for (i = 0; i < shi->Count; i++)
|
||||
trace( "%d: handle %x pid %x\n", i, (DWORD)shi->Handle[i].HandleValue, (DWORD)shi->Handle[i].UniqueProcessId );
|
||||
}
|
||||
|
||||
CloseHandle(EventHandle);
|
||||
|
||||
ReturnLength = 0xdeadbeef;
|
||||
status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi, SystemInformationLength, &ReturnLength);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status );
|
||||
for (i = 0, found = FALSE; i < shi->Count && !found; i++)
|
||||
found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) &&
|
||||
((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
|
||||
ok( !found, "Unexpectedly found event handle in handle list\n" );
|
||||
|
||||
status = pNtQuerySystemInformation(SystemExtendedHandleInformation, NULL, SystemInformationLength, &ReturnLength);
|
||||
ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status );
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, shi);
|
||||
}
|
||||
|
||||
@@ -684,6 +782,110 @@ static void test_query_logicalproc(void)
|
||||
HeapFree(GetProcessHeap(), 0, slpi);
|
||||
}
|
||||
|
||||
static void test_query_logicalprocex(void)
|
||||
{
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infoex, *infoex2;
|
||||
DWORD relationship, len2, len;
|
||||
NTSTATUS status;
|
||||
BOOL ret;
|
||||
|
||||
if (!pNtQuerySystemInformationEx)
|
||||
return;
|
||||
|
||||
len = 0;
|
||||
relationship = RelationProcessorCore;
|
||||
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
|
||||
ok(len > 0, "got %u\n", len);
|
||||
|
||||
len = 0;
|
||||
relationship = RelationAll;
|
||||
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), NULL, 0, &len);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
|
||||
ok(len > 0, "got %u\n", len);
|
||||
|
||||
len2 = 0;
|
||||
ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len2);
|
||||
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(len == len2, "got %u, expected %u\n", len2, len);
|
||||
|
||||
if (len && len == len2) {
|
||||
int j, i;
|
||||
|
||||
infoex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
||||
infoex2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
||||
|
||||
status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship), infoex, len, &len);
|
||||
ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
|
||||
|
||||
ret = pGetLogicalProcessorInformationEx(RelationAll, infoex2, &len2);
|
||||
ok(ret, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(!memcmp(infoex, infoex2, len), "returned info data mismatch\n");
|
||||
|
||||
for(i = 0; status == STATUS_SUCCESS && i < len; ){
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ex = (void*)(((char *)infoex) + i);
|
||||
|
||||
ok(ex->Relationship >= RelationProcessorCore && ex->Relationship <= RelationGroup,
|
||||
"Got invalid relationship value: 0x%x\n", ex->Relationship);
|
||||
if (!ex->Size)
|
||||
{
|
||||
ok(0, "got infoex[%u].Size=0\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
trace("infoex[%u].Size: %u\n", i, ex->Size);
|
||||
switch(ex->Relationship){
|
||||
case RelationProcessorCore:
|
||||
case RelationProcessorPackage:
|
||||
trace("infoex[%u].Relationship: 0x%x (Core == 0x0 or Package == 0x3)\n", i, ex->Relationship);
|
||||
trace("infoex[%u].Processor.Flags: 0x%x\n", i, ex->Processor.Flags);
|
||||
#ifndef __REACTOS__
|
||||
trace("infoex[%u].Processor.EfficiencyClass: 0x%x\n", i, ex->Processor.EfficiencyClass);
|
||||
#endif
|
||||
trace("infoex[%u].Processor.GroupCount: 0x%x\n", i, ex->Processor.GroupCount);
|
||||
for(j = 0; j < ex->Processor.GroupCount; ++j){
|
||||
trace("infoex[%u].Processor.GroupMask[%u].Mask: 0x%lx\n", i, j, ex->Processor.GroupMask[j].Mask);
|
||||
trace("infoex[%u].Processor.GroupMask[%u].Group: 0x%x\n", i, j, ex->Processor.GroupMask[j].Group);
|
||||
}
|
||||
break;
|
||||
case RelationNumaNode:
|
||||
trace("infoex[%u].Relationship: 0x%x (NumaNode)\n", i, ex->Relationship);
|
||||
trace("infoex[%u].NumaNode.NodeNumber: 0x%x\n", i, ex->NumaNode.NodeNumber);
|
||||
trace("infoex[%u].NumaNode.GroupMask.Mask: 0x%lx\n", i, ex->NumaNode.GroupMask.Mask);
|
||||
trace("infoex[%u].NumaNode.GroupMask.Group: 0x%x\n", i, ex->NumaNode.GroupMask.Group);
|
||||
break;
|
||||
case RelationCache:
|
||||
trace("infoex[%u].Relationship: 0x%x (Cache)\n", i, ex->Relationship);
|
||||
trace("infoex[%u].Cache.Level: 0x%x\n", i, ex->Cache.Level);
|
||||
trace("infoex[%u].Cache.Associativity: 0x%x\n", i, ex->Cache.Associativity);
|
||||
trace("infoex[%u].Cache.LineSize: 0x%x\n", i, ex->Cache.LineSize);
|
||||
trace("infoex[%u].Cache.CacheSize: 0x%x\n", i, ex->Cache.CacheSize);
|
||||
trace("infoex[%u].Cache.Type: 0x%x\n", i, ex->Cache.Type);
|
||||
trace("infoex[%u].Cache.GroupMask.Mask: 0x%lx\n", i, ex->Cache.GroupMask.Mask);
|
||||
trace("infoex[%u].Cache.GroupMask.Group: 0x%x\n", i, ex->Cache.GroupMask.Group);
|
||||
break;
|
||||
case RelationGroup:
|
||||
trace("infoex[%u].Relationship: 0x%x (Group)\n", i, ex->Relationship);
|
||||
trace("infoex[%u].Group.MaximumGroupCount: 0x%x\n", i, ex->Group.MaximumGroupCount);
|
||||
trace("infoex[%u].Group.ActiveGroupCount: 0x%x\n", i, ex->Group.ActiveGroupCount);
|
||||
for(j = 0; j < ex->Group.ActiveGroupCount; ++j){
|
||||
trace("infoex[%u].Group.GroupInfo[%u].MaximumProcessorCount: 0x%x\n", i, j, ex->Group.GroupInfo[j].MaximumProcessorCount);
|
||||
trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorCount: 0x%x\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorCount);
|
||||
trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorMask: 0x%lx\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorMask);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
i += ex->Size;
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, infoex);
|
||||
HeapFree(GetProcessHeap(), 0, infoex2);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_query_processor_power_info(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
@@ -904,12 +1106,32 @@ static void test_query_process_basic(void)
|
||||
ok( pbi.UniqueProcessId > 0, "Expected a ProcessID > 0, got 0\n");
|
||||
}
|
||||
|
||||
static void dump_vm_counters(const char *header, const VM_COUNTERS *pvi)
|
||||
{
|
||||
trace("%s:\n", header);
|
||||
trace("PeakVirtualSize : %lu\n", pvi->PeakVirtualSize);
|
||||
trace("VirtualSize : %lu\n", pvi->VirtualSize);
|
||||
trace("PageFaultCount : %u\n", pvi->PageFaultCount);
|
||||
trace("PeakWorkingSetSize : %lu\n", pvi->PeakWorkingSetSize);
|
||||
trace("WorkingSetSize : %lu\n", pvi->WorkingSetSize);
|
||||
trace("QuotaPeakPagedPoolUsage : %lu\n", pvi->QuotaPeakPagedPoolUsage);
|
||||
trace("QuotaPagedPoolUsage : %lu\n", pvi->QuotaPagedPoolUsage);
|
||||
trace("QuotaPeakNonPagePoolUsage : %lu\n", pvi->QuotaPeakNonPagedPoolUsage);
|
||||
trace("QuotaNonPagePoolUsage : %lu\n", pvi->QuotaNonPagedPoolUsage);
|
||||
trace("PagefileUsage : %lu\n", pvi->PagefileUsage);
|
||||
trace("PeakPagefileUsage : %lu\n", pvi->PeakPagefileUsage);
|
||||
}
|
||||
|
||||
static void test_query_process_vm(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG ReturnLength;
|
||||
VM_COUNTERS pvi;
|
||||
ULONG old_size = FIELD_OFFSET(VM_COUNTERS,PrivatePageCount);
|
||||
HANDLE process;
|
||||
SIZE_T prev_size;
|
||||
const SIZE_T alloc_size = 16 * 1024 * 1024;
|
||||
void *ptr;
|
||||
|
||||
status = pNtQueryInformationProcess(NULL, ProcessVmCounters, NULL, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
|
||||
@@ -935,11 +1157,72 @@ static void test_query_process_vm(void)
|
||||
ok( ReturnLength == old_size || ReturnLength == sizeof(pvi), "Inconsistent length %d\n", ReturnLength);
|
||||
|
||||
/* Check if we have some return values */
|
||||
trace("WorkingSetSize : %ld\n", pvi.WorkingSetSize);
|
||||
todo_wine
|
||||
{
|
||||
ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n");
|
||||
}
|
||||
dump_vm_counters("VM counters for GetCurrentProcess", &pvi);
|
||||
ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n");
|
||||
ok( pvi.PagefileUsage > 0, "Expected a PagefileUsage > 0\n");
|
||||
|
||||
process = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId());
|
||||
status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got %08x\n", status);
|
||||
CloseHandle(process);
|
||||
|
||||
process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
|
||||
status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS || broken(!process) /* XP */, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
CloseHandle(process);
|
||||
|
||||
memset(&pvi, 0, sizeof(pvi));
|
||||
process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
|
||||
status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
/* Check if we have some return values */
|
||||
dump_vm_counters("VM counters for GetCurrentProcessId", &pvi);
|
||||
ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n");
|
||||
ok( pvi.PagefileUsage > 0, "Expected a PagefileUsage > 0\n");
|
||||
|
||||
CloseHandle(process);
|
||||
|
||||
/* Check if we have real counters */
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
prev_size = pvi.VirtualSize;
|
||||
if (winetest_debug > 1)
|
||||
dump_vm_counters("VM counters before VirtualAlloc", &pvi);
|
||||
ptr = VirtualAlloc(NULL, alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError());
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
if (winetest_debug > 1)
|
||||
dump_vm_counters("VM counters after VirtualAlloc", &pvi);
|
||||
todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size,
|
||||
"Expected to be greater than %lu, got %lu\n", prev_size + alloc_size, pvi.VirtualSize);
|
||||
VirtualFree( ptr, 0, MEM_RELEASE);
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
prev_size = pvi.VirtualSize;
|
||||
if (winetest_debug > 1)
|
||||
dump_vm_counters("VM counters before VirtualAlloc", &pvi);
|
||||
ptr = VirtualAlloc(NULL, alloc_size, MEM_RESERVE, PAGE_READWRITE);
|
||||
ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError());
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
if (winetest_debug > 1)
|
||||
dump_vm_counters("VM counters after VirtualAlloc(MEM_RESERVE)", &pvi);
|
||||
todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size,
|
||||
"Expected to be greater than %lu, got %lu\n", prev_size + alloc_size, pvi.VirtualSize);
|
||||
prev_size = pvi.VirtualSize;
|
||||
|
||||
ptr = VirtualAlloc(ptr, alloc_size, MEM_COMMIT, PAGE_READWRITE);
|
||||
ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError());
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi, sizeof(pvi), NULL);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
if (winetest_debug > 1)
|
||||
dump_vm_counters("VM counters after VirtualAlloc(MEM_COMMIT)", &pvi);
|
||||
ok( pvi.VirtualSize == prev_size,
|
||||
"Expected to equal to %lu, got %lu\n", prev_size, pvi.VirtualSize);
|
||||
VirtualFree( ptr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
static void test_query_process_io(void)
|
||||
@@ -975,7 +1258,7 @@ static void test_query_process_io(void)
|
||||
ok( sizeof(pii) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
|
||||
|
||||
/* Check if we have some return values */
|
||||
trace("OtherOperationCount : 0x%x%08x\n", (DWORD)(pii.OtherOperationCount >> 32), (DWORD)pii.OtherOperationCount);
|
||||
trace("OtherOperationCount : 0x%s\n", wine_dbgstr_longlong(pii.OtherOperationCount));
|
||||
todo_wine
|
||||
{
|
||||
ok( pii.OtherOperationCount > 0, "Expected an OtherOperationCount > 0\n");
|
||||
@@ -1070,7 +1353,7 @@ static void test_query_process_debug_port(int argc, char **argv)
|
||||
|
||||
status = pNtQueryInformationProcess(NULL, ProcessDebugPort,
|
||||
&debug_port, sizeof(debug_port), NULL);
|
||||
ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status);
|
||||
ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort,
|
||||
&debug_port, sizeof(debug_port) - 1, NULL);
|
||||
@@ -1111,6 +1394,40 @@ static void test_query_process_debug_port(int argc, char **argv)
|
||||
ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
|
||||
}
|
||||
|
||||
static void test_query_process_priority(void)
|
||||
{
|
||||
PROCESS_PRIORITY_CLASS priority[2];
|
||||
ULONG ReturnLength;
|
||||
DWORD orig_priority;
|
||||
NTSTATUS status;
|
||||
BOOL ret;
|
||||
|
||||
status = pNtQueryInformationProcess(NULL, ProcessPriorityClass, NULL, sizeof(priority[0]), NULL);
|
||||
ok(status == STATUS_ACCESS_VIOLATION || broken(status == STATUS_INVALID_HANDLE) /* w2k3 */,
|
||||
"Expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
|
||||
|
||||
status = pNtQueryInformationProcess(NULL, ProcessPriorityClass, &priority, sizeof(priority[0]), NULL);
|
||||
ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status);
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass, &priority, 1, &ReturnLength);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass, &priority, sizeof(priority), &ReturnLength);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
|
||||
|
||||
orig_priority = GetPriorityClass(GetCurrentProcess());
|
||||
ret = SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
|
||||
ok(ret, "Failed to set priority class: %u\n", GetLastError());
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass, &priority, sizeof(priority[0]), &ReturnLength);
|
||||
ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok(priority[0].PriorityClass == PROCESS_PRIOCLASS_BELOW_NORMAL,
|
||||
"Expected PROCESS_PRIOCLASS_BELOW_NORMAL, got %u\n", priority[0].PriorityClass);
|
||||
|
||||
ret = SetPriorityClass(GetCurrentProcess(), orig_priority);
|
||||
ok(ret, "Failed to reset priority class: %u\n", GetLastError());
|
||||
}
|
||||
|
||||
static void test_query_process_handlecount(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
@@ -1293,27 +1610,27 @@ static void test_query_process_debug_object_handle(int argc, char **argv)
|
||||
|
||||
static void test_query_process_debug_flags(int argc, char **argv)
|
||||
{
|
||||
static const DWORD test_flags[] = { DEBUG_PROCESS,
|
||||
DEBUG_ONLY_THIS_PROCESS,
|
||||
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS,
|
||||
CREATE_SUSPENDED };
|
||||
DWORD debug_flags = 0xdeadbeef;
|
||||
char cmdline[MAX_PATH];
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFOA si = { 0 };
|
||||
NTSTATUS status;
|
||||
DEBUG_EVENT ev;
|
||||
DWORD result;
|
||||
BOOL ret;
|
||||
int i, j;
|
||||
|
||||
sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee");
|
||||
/* 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 +1639,123 @@ static void test_query_process_debug_flags(int argc, char **argv)
|
||||
|
||||
status = pNtQueryInformationProcess(NULL, ProcessDebugFlags,
|
||||
&debug_flags, sizeof(debug_flags), NULL);
|
||||
ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status);
|
||||
ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /* WOW64 */,
|
||||
"Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
|
||||
&debug_flags, sizeof(debug_flags) - 1, NULL);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
|
||||
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
|
||||
&debug_flags, sizeof(debug_flags) + 1, NULL);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
|
||||
|
||||
/* test ProcessDebugFlags of current process */
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
|
||||
&debug_flags, sizeof(debug_flags), NULL);
|
||||
ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "NtQueryInformationProcess failed, status %#x.\n", status);
|
||||
ok(debug_flags == TRUE|| broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected flag TRUE, got %x.\n", debug_flags);
|
||||
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 +1834,7 @@ static void test_mapprotection(void)
|
||||
status = pNtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
|
||||
ok( (status == STATUS_SUCCESS) || (status == STATUS_INVALID_INFO_CLASS), "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
size.u.LowPart = 0x1000;
|
||||
size.u.LowPart = 0x2000;
|
||||
size.u.HighPart = 0;
|
||||
status = pNtCreateSection ( &h,
|
||||
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
|
||||
@@ -1453,7 +1848,7 @@ static void test_mapprotection(void)
|
||||
|
||||
offset.u.LowPart = 0;
|
||||
offset.u.HighPart = 0;
|
||||
count = 0x1000;
|
||||
count = 0x2000;
|
||||
addr = NULL;
|
||||
status = pNtMapViewOfSection ( h, GetCurrentProcess(), &addr, 0, 0, &offset, &count, ViewShare, 0, PAGE_READWRITE);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
@@ -1476,7 +1871,7 @@ static void test_mapprotection(void)
|
||||
ok( retlen == sizeof(info), "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok((info.Protect & ~PAGE_NOCACHE) == PAGE_READWRITE, "addr.Protect is not PAGE_READWRITE, but 0x%x\n", info.Protect);
|
||||
|
||||
status = pNtUnmapViewOfSection (GetCurrentProcess(), addr);
|
||||
status = pNtUnmapViewOfSection( GetCurrentProcess(), (char *)addr + 0x1050 );
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
pNtClose (h);
|
||||
|
||||
@@ -1488,12 +1883,17 @@ static void test_queryvirtualmemory(void)
|
||||
{
|
||||
NTSTATUS status;
|
||||
SIZE_T readcount;
|
||||
static const WCHAR windowsW[] = {'w','i','n','d','o','w','s'};
|
||||
static const char teststring[] = "test string";
|
||||
static char datatestbuf[42] = "abc";
|
||||
static char rwtestbuf[42];
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
char stackbuf[42];
|
||||
HMODULE module;
|
||||
char buffer_name[sizeof(MEMORY_SECTION_NAME) + MAX_PATH * sizeof(WCHAR)];
|
||||
MEMORY_SECTION_NAME *msn = (MEMORY_SECTION_NAME *)buffer_name;
|
||||
BOOL found;
|
||||
int i;
|
||||
|
||||
module = GetModuleHandleA( "ntdll.dll" );
|
||||
trace("Check flags of the PE header of NTDLL.DLL at %p\n", module);
|
||||
@@ -1567,6 +1967,43 @@ static void test_queryvirtualmemory(void)
|
||||
"mbi.Protect is 0x%x\n", mbi.Protect);
|
||||
}
|
||||
else skip( "bss is outside of module\n" ); /* this can happen on Mac OS */
|
||||
|
||||
trace("Check section name of NTDLL.DLL with invalid size\n");
|
||||
module = GetModuleHandleA( "ntdll.dll" );
|
||||
memset(msn, 0, sizeof(*msn));
|
||||
readcount = 0;
|
||||
status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn, sizeof(*msn), &readcount);
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "Expected STATUS_BUFFER_OVERFLOW, got %08x\n", status);
|
||||
ok( readcount > 0, "Expected readcount to be > 0\n");
|
||||
|
||||
trace("Check section name of NTDLL.DLL with invalid size\n");
|
||||
module = GetModuleHandleA( "ntdll.dll" );
|
||||
memset(msn, 0, sizeof(*msn));
|
||||
readcount = 0;
|
||||
status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn, sizeof(*msn) - 1, &readcount);
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
|
||||
ok( readcount > 0, "Expected readcount to be > 0\n");
|
||||
|
||||
trace("Check section name of NTDLL.DLL\n");
|
||||
module = GetModuleHandleA( "ntdll.dll" );
|
||||
memset(msn, 0x55, sizeof(*msn));
|
||||
memset(buffer_name, 0x77, sizeof(buffer_name));
|
||||
readcount = 0;
|
||||
status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn, sizeof(buffer_name), &readcount);
|
||||
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok( readcount > 0, "Expected readcount to be > 0\n");
|
||||
trace ("Section Name: %s\n", wine_dbgstr_w(msn->SectionFileName.Buffer));
|
||||
pRtlDowncaseUnicodeString( &msn->SectionFileName, &msn->SectionFileName, FALSE );
|
||||
for (found = FALSE, i = (msn->SectionFileName.Length - sizeof(windowsW)) / sizeof(WCHAR); i >= 0; i--)
|
||||
found |= !memcmp( &msn->SectionFileName.Buffer[i], windowsW, sizeof(windowsW) );
|
||||
ok( found, "Section name does not contain \"Windows\"\n");
|
||||
|
||||
trace("Check section name of non mapped memory\n");
|
||||
memset(msn, 0, sizeof(*msn));
|
||||
readcount = 0;
|
||||
status = pNtQueryVirtualMemory(NtCurrentProcess(), &buffer_name, MemorySectionName, msn, sizeof(buffer_name), &readcount);
|
||||
ok( status == STATUS_INVALID_ADDRESS, "Expected STATUS_INVALID_ADDRESS, got %08x\n", status);
|
||||
ok( readcount == 0 || broken(readcount != 0) /* wow64 */, "Expected readcount to be 0\n");
|
||||
}
|
||||
|
||||
static void test_affinity(void)
|
||||
@@ -1780,6 +2217,39 @@ static void test_thread_start_address(void)
|
||||
CloseHandle(thread);
|
||||
}
|
||||
|
||||
static void test_query_data_alignment(void)
|
||||
{
|
||||
ULONG ReturnLength;
|
||||
NTSTATUS status;
|
||||
DWORD value;
|
||||
|
||||
value = 0xdeadbeef;
|
||||
status = pNtQuerySystemInformation(SystemRecommendedSharedDataAlignment, &value, sizeof(value), &ReturnLength);
|
||||
ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok(sizeof(value) == ReturnLength, "Inconsistent length %u\n", ReturnLength);
|
||||
ok(value == 64, "Expected 64, got %u\n", value);
|
||||
}
|
||||
|
||||
static void test_working_set_limit(void)
|
||||
{
|
||||
DWORD_PTR lower = 0, upper = ~(DWORD_PTR)0;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
SIZE_T readcount;
|
||||
NTSTATUS status;
|
||||
|
||||
while (lower != upper)
|
||||
{
|
||||
DWORD_PTR check = (lower >> 1) + (upper >> 1) + (lower & upper & 1);
|
||||
status = pNtQueryVirtualMemory(NtCurrentProcess(), (void *)check, MemoryBasicInformation,
|
||||
&mbi, sizeof(MEMORY_BASIC_INFORMATION), &readcount);
|
||||
if (status == STATUS_INVALID_PARAMETER) upper = check;
|
||||
else lower = check + 1;
|
||||
}
|
||||
|
||||
trace("working set limit is %p\n", (void *)upper);
|
||||
ok(upper != ~(DWORD_PTR)0, "expected != ~(DWORD_PTR)0\n");
|
||||
}
|
||||
|
||||
START_TEST(info)
|
||||
{
|
||||
char **argv;
|
||||
@@ -1825,6 +2295,10 @@ START_TEST(info)
|
||||
trace("Starting test_query_handle()\n");
|
||||
test_query_handle();
|
||||
|
||||
/* 0x40 SystemHandleInformation */
|
||||
trace("Starting test_query_handle_ex()\n");
|
||||
test_query_handle_ex();
|
||||
|
||||
/* 0x15 SystemCacheInformation */
|
||||
trace("Starting test_query_cache()\n");
|
||||
test_query_cache();
|
||||
@@ -1844,6 +2318,7 @@ START_TEST(info)
|
||||
/* 0x49 SystemLogicalProcessorInformation */
|
||||
trace("Starting test_query_logicalproc()\n");
|
||||
test_query_logicalproc();
|
||||
test_query_logicalprocex();
|
||||
|
||||
/* NtPowerInformation */
|
||||
|
||||
@@ -1873,6 +2348,10 @@ START_TEST(info)
|
||||
trace("Starting test_process_debug_port()\n");
|
||||
test_query_process_debug_port(argc, argv);
|
||||
|
||||
/* 0x12 ProcessPriorityClass */
|
||||
trace("Starting test_query_process_priority()\n");
|
||||
test_query_process_priority();
|
||||
|
||||
/* 0x14 ProcessHandleCount */
|
||||
trace("Starting test_query_process_handlecount()\n");
|
||||
test_query_process_handlecount();
|
||||
@@ -1911,4 +2390,10 @@ START_TEST(info)
|
||||
|
||||
trace("Starting test_thread_start_address()\n");
|
||||
test_thread_start_address();
|
||||
|
||||
trace("Starting test_query_data_alignment()\n");
|
||||
test_query_data_alignment();
|
||||
|
||||
trace("Starting test_working_set_limit()\n");
|
||||
test_working_set_limit();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ static VOID (WINAPI *pRtlFreeAnsiString)(PSTRING);
|
||||
static NTSTATUS (WINAPI *pRtlInt64ToUnicodeString)(ULONGLONG, ULONG, UNICODE_STRING *);
|
||||
static NTSTATUS (WINAPI *pRtlLargeIntegerToChar)(ULONGLONG *, ULONG, ULONG, PCHAR);
|
||||
static NTSTATUS (WINAPI *pRtlUnicodeStringToAnsiString)(STRING *, const UNICODE_STRING *, BOOLEAN);
|
||||
static void (WINAPI *p_alldvrm)(LONGLONG, LONGLONG);
|
||||
static void (WINAPI *p_aulldvrm)(ULONGLONG, ULONGLONG);
|
||||
|
||||
|
||||
static void InitFunctionPtrs(void)
|
||||
@@ -45,6 +47,8 @@ static void InitFunctionPtrs(void)
|
||||
pRtlInt64ToUnicodeString = (void *)GetProcAddress(hntdll, "RtlInt64ToUnicodeString");
|
||||
pRtlLargeIntegerToChar = (void *)GetProcAddress(hntdll, "RtlLargeIntegerToChar");
|
||||
pRtlUnicodeStringToAnsiString = (void *)GetProcAddress(hntdll, "RtlUnicodeStringToAnsiString");
|
||||
p_alldvrm = (void *)GetProcAddress(hntdll, "_alldvrm");
|
||||
p_aulldvrm = (void *)GetProcAddress(hntdll, "_aulldvrm");
|
||||
} /* if */
|
||||
}
|
||||
|
||||
@@ -113,10 +117,9 @@ static void test_RtlExtendedMagicDivide(void)
|
||||
for (i = 0; i < NB_MAGIC_DIVIDE; i++) {
|
||||
result = pRtlExtendedMagicDivide(magic_divide[i].a, magic_divide[i].b, magic_divide[i].shift);
|
||||
ok(result == magic_divide[i].result,
|
||||
"call failed: RtlExtendedMagicDivide(0x%x%08x, 0x%x%08x, %d) has result 0x%x%08x, expected 0x%x%08x\n",
|
||||
(DWORD)(magic_divide[i].a >> 32), (DWORD)magic_divide[i].a, (DWORD)(magic_divide[i].b >> 32),
|
||||
(DWORD)magic_divide[i].b, magic_divide[i].shift, (DWORD)(result >> 32), (DWORD)result,
|
||||
(DWORD)(magic_divide[i].result >> 32), (DWORD)magic_divide[i].result);
|
||||
"call failed: RtlExtendedMagicDivide(0x%s, 0x%s, %d) has result 0x%s, expected 0x%s\n",
|
||||
wine_dbgstr_longlong(magic_divide[i].a), wine_dbgstr_longlong(magic_divide[i].b), magic_divide[i].shift,
|
||||
wine_dbgstr_longlong(result), wine_dbgstr_longlong(magic_divide[i].result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,14 +335,12 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t
|
||||
} /* if */
|
||||
} else {
|
||||
ok(result == largeint2str->result,
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) has result %x, expected: %x\n",
|
||||
test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value,
|
||||
largeint2str->base, result, largeint2str->result);
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) has result %x, expected: %x\n",
|
||||
test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, result, largeint2str->result);
|
||||
if (result == STATUS_SUCCESS) {
|
||||
ok(unicode_string.Buffer[unicode_string.Length/sizeof(WCHAR)] == '\0',
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string \"%s\" is not NULL terminated\n",
|
||||
test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value,
|
||||
largeint2str->base, ansi_str.Buffer);
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string \"%s\" is not NULL terminated\n",
|
||||
test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base, ansi_str.Buffer);
|
||||
} /* if */
|
||||
} /* if */
|
||||
ok(memcmp(unicode_string.Buffer, expected_unicode_string.Buffer, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
|
||||
@@ -347,12 +348,12 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const largeint2str_t
|
||||
test_num, (DWORD)(largeint2str->value >>32), (DWORD)largeint2str->value, largeint2str->base,
|
||||
ansi_str.Buffer, expected_ansi_str.Buffer);
|
||||
ok(unicode_string.Length == expected_unicode_string.Length,
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has Length %d, expected: %d\n",
|
||||
test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base,
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string has Length %d, expected: %d\n",
|
||||
test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
|
||||
unicode_string.Length, expected_unicode_string.Length);
|
||||
ok(unicode_string.MaximumLength == expected_unicode_string.MaximumLength,
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has MaximumLength %d, expected: %d\n",
|
||||
test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base,
|
||||
"(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string has MaximumLength %d, expected: %d\n",
|
||||
test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
|
||||
unicode_string.MaximumLength, expected_unicode_string.MaximumLength);
|
||||
pRtlFreeAnsiString(&expected_ansi_str);
|
||||
pRtlFreeAnsiString(&ansi_str);
|
||||
@@ -392,12 +393,12 @@ static void one_RtlLargeIntegerToChar_test(int test_num, const largeint2str_t *l
|
||||
result = pRtlLargeIntegerToChar(&value, largeint2str->base, largeint2str->MaximumLength, dest_str);
|
||||
} /* if */
|
||||
ok(result == largeint2str->result,
|
||||
"(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) has result %x, expected: %x\n",
|
||||
test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base,
|
||||
"(test %d): RtlLargeIntegerToChar(0x%s, %d, %d, [out]) has result %x, expected: %x\n",
|
||||
test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
|
||||
largeint2str->MaximumLength, result, largeint2str->result);
|
||||
ok(memcmp(dest_str, largeint2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
|
||||
"(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(largeint2str->value >> 32), (DWORD)largeint2str->value, largeint2str->base,
|
||||
"(test %d): RtlLargeIntegerToChar(0x%s, %d, %d, [out]) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
|
||||
largeint2str->MaximumLength, dest_str, largeint2str->Buffer);
|
||||
}
|
||||
|
||||
@@ -415,30 +416,89 @@ static void test_RtlLargeIntegerToChar(void)
|
||||
value = largeint2str[0].value;
|
||||
result = pRtlLargeIntegerToChar(&value, 20, largeint2str[0].MaximumLength, NULL);
|
||||
ok(result == STATUS_INVALID_PARAMETER,
|
||||
"(test a): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
(DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20,
|
||||
"(test a): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
wine_dbgstr_longlong(largeint2str[0].value), 20,
|
||||
largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER);
|
||||
|
||||
result = pRtlLargeIntegerToChar(&value, 20, 0, NULL);
|
||||
ok(result == STATUS_INVALID_PARAMETER,
|
||||
"(test b): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
(DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20,
|
||||
"(test b): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
wine_dbgstr_longlong(largeint2str[0].value), 20,
|
||||
largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER);
|
||||
|
||||
result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, 0, NULL);
|
||||
ok(result == STATUS_BUFFER_OVERFLOW,
|
||||
"(test c): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
(DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value,
|
||||
largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW);
|
||||
"(test c): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
wine_dbgstr_longlong(largeint2str[0].value), largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW);
|
||||
|
||||
result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, largeint2str[0].MaximumLength, NULL);
|
||||
ok(result == STATUS_ACCESS_VIOLATION,
|
||||
"(test d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
(DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value,
|
||||
"(test d): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected: %x\n",
|
||||
wine_dbgstr_longlong(largeint2str[0].value),
|
||||
largeint2str[0].base, largeint2str[0].MaximumLength, result, STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#include "pshpack1.h"
|
||||
struct lldvrm_thunk
|
||||
{
|
||||
BYTE push_ebx; /* pushl %ebx */
|
||||
DWORD push_esp1; /* pushl 24(%esp) */
|
||||
DWORD push_esp2; /* pushl 24(%esp) */
|
||||
DWORD push_esp3; /* pushl 24(%esp) */
|
||||
DWORD push_esp4; /* pushl 24(%esp) */
|
||||
DWORD call; /* call 24(%esp) */
|
||||
WORD mov_ecx_eax; /* movl %ecx,%eax */
|
||||
WORD mov_ebx_edx; /* movl %ebx,%edx */
|
||||
BYTE pop_ebx; /* popl %ebx */
|
||||
BYTE ret; /* ret */
|
||||
};
|
||||
#include "poppack.h"
|
||||
|
||||
static void test__alldvrm(void)
|
||||
{
|
||||
struct lldvrm_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
ULONGLONG (CDECL *call_lldvrm_func)(void *func, ULONGLONG, ULONGLONG) = (void *)thunk;
|
||||
ULONGLONG ret;
|
||||
|
||||
memset(thunk, 0x90, sizeof(*thunk));
|
||||
thunk->push_ebx = 0x53; /* pushl %ebx */
|
||||
thunk->push_esp1 = 0x182474ff; /* pushl 24(%esp) */
|
||||
thunk->push_esp2 = 0x182474ff; /* pushl 24(%esp) */
|
||||
thunk->push_esp3 = 0x182474ff; /* pushl 24(%esp) */
|
||||
thunk->push_esp4 = 0x182474ff; /* pushl 24(%esp) */
|
||||
thunk->call = 0x182454ff; /* call 24(%esp) */
|
||||
thunk->pop_ebx = 0x5b; /* popl %ebx */
|
||||
thunk->ret = 0xc3; /* ret */
|
||||
|
||||
ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, 3);
|
||||
ok(ret == 0x61172255b66c77ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, -3);
|
||||
ok(ret == 0xff9ee8ddaa499389ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
|
||||
ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, 3);
|
||||
ok(ret == 0x61172255b66c77ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, -3);
|
||||
ok(ret == 0, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
|
||||
thunk->mov_ecx_eax = 0xc889;
|
||||
thunk->mov_ebx_edx = 0xda89;
|
||||
|
||||
ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, 3);
|
||||
ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, -3);
|
||||
ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
|
||||
ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, 3);
|
||||
ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, -3);
|
||||
ok(ret == 0x123456701234567ULL, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
|
||||
}
|
||||
#endif /* __i386__ */
|
||||
|
||||
|
||||
START_TEST(large_int)
|
||||
{
|
||||
InitFunctionPtrs();
|
||||
@@ -449,4 +509,8 @@ START_TEST(large_int)
|
||||
test_RtlInt64ToUnicodeString();
|
||||
if (pRtlLargeIntegerToChar)
|
||||
test_RtlLargeIntegerToChar();
|
||||
|
||||
#ifdef __i386__
|
||||
test__alldvrm();
|
||||
#endif /* __i386__ */
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x500 /* For NTSTATUS */
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -267,7 +267,7 @@ static void test_RtlGetFullPathName_U(void)
|
||||
{ "c:/test/ .... .. ", "c:\\test\\", NULL},
|
||||
{ "c:/test/..", "c:\\", NULL},
|
||||
{ "c:/test/.. ", "c:\\test\\", NULL},
|
||||
{ "c:/TEST", "c:\\test", "test"},
|
||||
{ "c:/TEST", "c:\\TEST", "TEST"},
|
||||
{ "c:/test/file", "c:\\test\\file", "file"},
|
||||
{ "c:/test./file", "c:\\test\\file", "file"},
|
||||
{ "c:/test.. /file", "c:\\test.. \\file","file"},
|
||||
@@ -281,6 +281,7 @@ static void test_RtlGetFullPathName_U(void)
|
||||
{ "c:///test\\..\\file\\..\\//", "c:\\", NULL},
|
||||
{ "c:/test../file", "c:\\test.\\file", "file",
|
||||
"c:\\test..\\file", "file"}, /* vista */
|
||||
{ "c:\\test", "c:\\test", "test"},
|
||||
{ NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -327,14 +328,14 @@ static void test_RtlGetFullPathName_U(void)
|
||||
"Wrong result %d/%d for \"%s\"\n", ret, len, test->path );
|
||||
ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
|
||||
"RtlUnicodeToMultiByteN failed\n");
|
||||
ok(!lstrcmpiA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpiA(rbufferA,test->alt_rname)),
|
||||
ok(!lstrcmpA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpA(rbufferA,test->alt_rname)),
|
||||
"Got \"%s\" expected \"%s\"\n",rbufferA,test->rname);
|
||||
if (file_part)
|
||||
{
|
||||
ok(pRtlUnicodeToMultiByteN(rfileA,MAX_PATH,&reslen,file_part,(lstrlenW(file_part) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
|
||||
"RtlUnicodeToMultiByteN failed\n");
|
||||
ok((test->rfile && !lstrcmpiA(rfileA,test->rfile)) ||
|
||||
(test->alt_rfile && !lstrcmpiA(rfileA,test->alt_rfile)),
|
||||
ok((test->rfile && !lstrcmpA(rfileA,test->rfile)) ||
|
||||
(test->alt_rfile && !lstrcmpA(rfileA,test->alt_rfile)),
|
||||
"Got \"%s\" expected \"%s\"\n",rfileA,test->rfile);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -75,6 +75,7 @@ static NTSTATUS (WINAPI *pNtCreateNamedPipeFile) (PHANDLE handle, ULONG access,
|
||||
static NTSTATUS (WINAPI *pNtQueryInformationFile) (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
|
||||
static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class);
|
||||
static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
|
||||
static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
|
||||
static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
|
||||
|
||||
static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
|
||||
@@ -95,6 +96,7 @@ static BOOL init_func_ptrs(void)
|
||||
loadfunc(NtQueryInformationFile)
|
||||
loadfunc(NtSetInformationFile)
|
||||
loadfunc(NtCancelIoFile)
|
||||
loadfunc(NtCancelIoFileEx)
|
||||
loadfunc(RtlInitUnicodeString)
|
||||
|
||||
/* not fatal */
|
||||
@@ -104,6 +106,11 @@ static BOOL init_func_ptrs(void)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOL is_signaled( HANDLE obj )
|
||||
{
|
||||
return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
|
||||
't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
|
||||
static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
|
||||
@@ -133,6 +140,21 @@ static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options)
|
||||
return res;
|
||||
}
|
||||
|
||||
static BOOL ioapc_called;
|
||||
static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
|
||||
{
|
||||
ioapc_called = TRUE;
|
||||
}
|
||||
|
||||
static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
ioapc_called = FALSE;
|
||||
|
||||
return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void test_create_invalid(void)
|
||||
{
|
||||
IO_STATUS_BLOCK iosb;
|
||||
@@ -200,6 +222,7 @@ static void test_create(void)
|
||||
int j, k;
|
||||
FILE_PIPE_LOCAL_INFORMATION info;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
|
||||
static const DWORD sharing[] = { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
|
||||
@@ -210,12 +233,15 @@ static void test_create(void)
|
||||
HANDLE hclient;
|
||||
BOOL should_succeed = TRUE;
|
||||
|
||||
res = create_pipe(&hserver, sharing[j], FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
res = create_pipe(&hserver, sharing[j], 0);
|
||||
if (res) {
|
||||
ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = listen_pipe(hserver, hEvent, &iosb, FALSE);
|
||||
ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
|
||||
|
||||
res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
|
||||
ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
|
||||
ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
|
||||
@@ -245,21 +271,7 @@ static void test_create(void)
|
||||
CloseHandle(hserver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL ioapc_called;
|
||||
static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
|
||||
{
|
||||
ioapc_called = TRUE;
|
||||
}
|
||||
|
||||
static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
ioapc_called = FALSE;
|
||||
|
||||
return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
|
||||
CloseHandle(hEvent);
|
||||
}
|
||||
|
||||
static void test_overlapped(void)
|
||||
@@ -305,10 +317,12 @@ static void test_overlapped(void)
|
||||
|
||||
if (hClient != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SetEvent(hEvent);
|
||||
memset(&iosb, 0x55, sizeof(iosb));
|
||||
res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
|
||||
ok(res == STATUS_PIPE_CONNECTED, "NtFsControlFile returned %x\n", res);
|
||||
ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
|
||||
ok(!is_signaled(hEvent), "hEvent not signaled\n");
|
||||
|
||||
CloseHandle(hClient);
|
||||
}
|
||||
@@ -317,6 +331,73 @@ static void test_overlapped(void)
|
||||
CloseHandle(hEvent);
|
||||
}
|
||||
|
||||
static void test_completion(void)
|
||||
{
|
||||
static const char buf[] = "testdata";
|
||||
FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
|
||||
HANDLE port, pipe, client;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
OVERLAPPED ov, *pov;
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
DWORD num_bytes;
|
||||
ULONG_PTR key;
|
||||
DWORD dwret;
|
||||
BOOL ret;
|
||||
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(ov.hEvent != INVALID_HANDLE_VALUE, "CreateEvent failed, error %u\n", GetLastError());
|
||||
|
||||
status = create_pipe(&pipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
|
||||
ok(!status, "NtCreateNamedPipeFile returned %x\n", status);
|
||||
status = listen_pipe(pipe, ov.hEvent, &iosb, FALSE);
|
||||
ok(status == STATUS_PENDING, "NtFsControlFile returned %x\n", status);
|
||||
|
||||
client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0,
|
||||
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %u\n", GetLastError());
|
||||
dwret = WaitForSingleObject(ov.hEvent, 0);
|
||||
ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
|
||||
|
||||
port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0);
|
||||
ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
|
||||
|
||||
ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
|
||||
ok(ret, "WriteFile failed, error %u\n", GetLastError());
|
||||
ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
|
||||
|
||||
key = 0;
|
||||
pov = NULL;
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
|
||||
ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
|
||||
ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key);
|
||||
ok(pov == &ov, "expected %p, got %p\n", &ov, pov);
|
||||
|
||||
info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
|
||||
status = pNtSetInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
info.Flags = 0;
|
||||
status = pNtQueryInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
|
||||
|
||||
ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
|
||||
ok(ret, "WriteFile failed, error %u\n", GetLastError());
|
||||
ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
|
||||
|
||||
pov = (void *)0xdeadbeef;
|
||||
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
|
||||
ok(!ret, "GetQueuedCompletionStatus succeeded\n");
|
||||
ok(pov == NULL, "expected NULL, got %p\n", pov);
|
||||
|
||||
CloseHandle(ov.hEvent);
|
||||
CloseHandle(client);
|
||||
CloseHandle(pipe);
|
||||
CloseHandle(port);
|
||||
}
|
||||
|
||||
static BOOL userapc_called;
|
||||
static void CALLBACK userapc(ULONG_PTR dwParam)
|
||||
{
|
||||
@@ -498,6 +579,21 @@ static void test_cancelio(void)
|
||||
|
||||
ok(ioapc_called, "IOAPC didn't run\n");
|
||||
|
||||
CloseHandle(hPipe);
|
||||
|
||||
res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
|
||||
ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
|
||||
|
||||
memset(&iosb, 0x55, sizeof(iosb));
|
||||
res = listen_pipe(hPipe, hEvent, &iosb, FALSE);
|
||||
ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
|
||||
|
||||
res = pNtCancelIoFileEx(hPipe, &iosb, &cancel_sb);
|
||||
ok(!res, "NtCancelIoFileEx returned %x\n", res);
|
||||
|
||||
ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
|
||||
ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
|
||||
|
||||
CloseHandle(hEvent);
|
||||
CloseHandle(hPipe);
|
||||
}
|
||||
@@ -688,6 +784,389 @@ static void test_filepipeinfo(void)
|
||||
CloseHandle(hServer);
|
||||
}
|
||||
|
||||
static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
|
||||
{
|
||||
int *count = arg;
|
||||
(*count)++;
|
||||
ok( !reserved, "reserved is not 0: %x\n", reserved );
|
||||
}
|
||||
|
||||
static void test_peek(HANDLE pipe, BOOL is_msgmode)
|
||||
{
|
||||
FILE_PIPE_PEEK_BUFFER buf;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
NTSTATUS status;
|
||||
|
||||
memset(&iosb, 0x55, sizeof(iosb));
|
||||
status = NtFsControlFile(pipe, NULL, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
|
||||
ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
|
||||
ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
|
||||
ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
|
||||
|
||||
ResetEvent(event);
|
||||
memset(&iosb, 0x55, sizeof(iosb));
|
||||
status = NtFsControlFile(pipe, event, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
|
||||
ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
|
||||
ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
|
||||
ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
|
||||
todo_wine_if(!is_msgmode)
|
||||
ok(is_signaled(event), "event is not signaled\n");
|
||||
|
||||
CloseHandle(event);
|
||||
}
|
||||
|
||||
#define PIPENAME "\\\\.\\pipe\\ntdll_tests_pipe.c"
|
||||
|
||||
static BOOL create_pipe_pair( HANDLE *read, HANDLE *write, ULONG flags, ULONG type, ULONG size )
|
||||
{
|
||||
const BOOL server_reader = flags & PIPE_ACCESS_INBOUND;
|
||||
HANDLE client, server;
|
||||
|
||||
server = CreateNamedPipeA(PIPENAME, flags, PIPE_WAIT | type,
|
||||
1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
|
||||
ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
|
||||
|
||||
client = CreateFileA(PIPENAME, server_reader ? GENERIC_WRITE : GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0,
|
||||
NULL, OPEN_EXISTING, flags & FILE_FLAG_OVERLAPPED, 0);
|
||||
ok(client != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
|
||||
|
||||
if(server_reader)
|
||||
{
|
||||
*read = server;
|
||||
*write = client;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(type & PIPE_READMODE_MESSAGE)
|
||||
{
|
||||
DWORD read_mode = PIPE_READMODE_MESSAGE;
|
||||
ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n");
|
||||
}
|
||||
|
||||
*read = client;
|
||||
*write = server;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void read_pipe_test(ULONG pipe_flags, ULONG pipe_type)
|
||||
{
|
||||
IO_STATUS_BLOCK iosb, iosb2;
|
||||
HANDLE handle, read, write;
|
||||
HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
int apc_count = 0;
|
||||
char buffer[128];
|
||||
DWORD written;
|
||||
BOOL ret;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
|
||||
|
||||
/* try read with no data */
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ok( is_signaled( read ), "read handle is not signaled\n" );
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
/* iosb updated here by async i/o */
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
apc_count = 0;
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* with no event, the pipe handle itself gets signaled */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
status = NtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( read ), "read handle is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
/* iosb updated here by async i/o */
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( read ), "read handle is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
apc_count = 0;
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* now read with data ready */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ResetEvent( event );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
|
||||
test_peek(read, pipe_type & PIPE_TYPE_MESSAGE);
|
||||
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* now partial read with data ready */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ResetEvent( event );
|
||||
ret = WriteFile( write, buffer, 2, &written, NULL );
|
||||
ok(ret && written == 2, "WriteFile error %d\n", GetLastError());
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
if (pipe_type & PIPE_READMODE_MESSAGE)
|
||||
{
|
||||
ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(iosb).Status );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
}
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
apc_count = 0;
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, FALSE ); /* non-alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc not called\n" );
|
||||
|
||||
/* try read with no data */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
ret = WriteFile( write, buffer, 1, &written, NULL );
|
||||
ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
|
||||
/* partial read is good enough */
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
|
||||
/* read from disconnected pipe */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
CloseHandle( write );
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
CloseHandle( read );
|
||||
|
||||
/* read from disconnected pipe, with invalid event handle */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = NtReadFile( read, (HANDLE)0xdeadbeef, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
CloseHandle( read );
|
||||
|
||||
/* read from closed handle */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
SetEvent( event );
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
|
||||
ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on invalid handle */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
|
||||
/* disconnect while async read is in progress */
|
||||
if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
CloseHandle( write );
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
todo_wine_if(!(pipe_type & PIPE_TYPE_MESSAGE) && (pipe_flags & PIPE_ACCESS_OUTBOUND))
|
||||
ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
CloseHandle( read );
|
||||
|
||||
if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
|
||||
ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||
ok(ret, "Failed to duplicate handle: %d\n", GetLastError());
|
||||
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = NtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
/* Cancel by other handle */
|
||||
status = pNtCancelIoFile( read, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status);
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
/* Close queued handle */
|
||||
CloseHandle( read );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
status = pNtCancelIoFile( read, &iosb2 );
|
||||
ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
|
||||
status = pNtCancelIoFile( handle, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
CloseHandle( handle );
|
||||
CloseHandle( write );
|
||||
|
||||
if (pNtCancelIoFileEx)
|
||||
{
|
||||
/* Basic Cancel Ex */
|
||||
if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
|
||||
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 1, "apc was not called\n" );
|
||||
|
||||
/* Duplicate iosb */
|
||||
apc_count = 0;
|
||||
U(iosb).Status = 0xdeadbabe;
|
||||
iosb.Information = 0xdeadbeef;
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
|
||||
ok( status == STATUS_PENDING, "wrong status %x\n", status );
|
||||
ok( !is_signaled( event ), "event is signaled\n" );
|
||||
ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
|
||||
ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
|
||||
Sleep(1); /* FIXME: needed for wine to run the i/o apc */
|
||||
ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
|
||||
ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
|
||||
ok( is_signaled( event ), "event is not signaled\n" );
|
||||
ok( !apc_count, "apc was called\n" );
|
||||
SleepEx( 1, TRUE ); /* alertable sleep */
|
||||
ok( apc_count == 2, "apc was not called\n" );
|
||||
|
||||
CloseHandle( read );
|
||||
CloseHandle( write );
|
||||
}
|
||||
|
||||
CloseHandle(event);
|
||||
}
|
||||
|
||||
START_TEST(pipe)
|
||||
{
|
||||
if (!init_func_ptrs())
|
||||
@@ -702,6 +1181,9 @@ START_TEST(pipe)
|
||||
trace("starting overlapped tests\n");
|
||||
test_overlapped();
|
||||
|
||||
trace("starting completion tests\n");
|
||||
test_completion();
|
||||
|
||||
trace("starting FILE_PIPE_INFORMATION tests\n");
|
||||
test_filepipeinfo();
|
||||
|
||||
@@ -716,4 +1198,17 @@ START_TEST(pipe)
|
||||
|
||||
trace("starting cancelio tests\n");
|
||||
test_cancelio();
|
||||
|
||||
trace("starting byte read in byte mode client -> server\n");
|
||||
read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE);
|
||||
trace("starting byte read in message mode client -> server\n");
|
||||
read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE);
|
||||
trace("starting message read in message mode client -> server\n");
|
||||
read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
|
||||
trace("starting byte read in byte mode server -> client\n");
|
||||
read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE);
|
||||
trace("starting byte read in message mode server -> client\n");
|
||||
read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE);
|
||||
trace("starting message read in message mode server -> client\n");
|
||||
read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Unit test suite for process functions
|
||||
*
|
||||
* Copyright 2017 Michael Müller
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntdll_test.h"
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
||||
static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE);
|
||||
static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE);
|
||||
static NTSTATUS (WINAPI *pNtSuspendThread)(HANDLE,PULONG);
|
||||
static NTSTATUS (WINAPI *pNtResumeThread)(HANDLE);
|
||||
|
||||
static void test_NtSuspendProcess(char *process_name)
|
||||
{
|
||||
PROCESS_INFORMATION info;
|
||||
DEBUG_EVENT ev;
|
||||
STARTUPINFOA startup;
|
||||
NTSTATUS status;
|
||||
HANDLE event;
|
||||
char buffer[MAX_PATH];
|
||||
ULONG count;
|
||||
DWORD ret;
|
||||
|
||||
status = pNtResumeProcess(GetCurrentProcess());
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
event = CreateEventA(NULL, TRUE, FALSE, "wine_suspend_event");
|
||||
ok(!!event, "Failed to create event: %u\n", GetLastError());
|
||||
|
||||
memset(&startup, 0, sizeof(startup));
|
||||
startup.cb = sizeof(startup);
|
||||
|
||||
sprintf(buffer, "%s tests/process.c dummy_process wine_suspend_event", process_name);
|
||||
ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
|
||||
ok(ret, "CreateProcess failed with error %u\n", GetLastError());
|
||||
|
||||
ret = WaitForSingleObject(event, 500);
|
||||
ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
|
||||
|
||||
status = pNtSuspendProcess(info.hProcess);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
ResetEvent(event);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
status = NtResumeThread(info.hThread, &count);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
ok(count == 1, "Expected count 1, got %d\n", count);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
status = pNtSuspendThread(info.hThread, &count);
|
||||
ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status);
|
||||
ok(count == 0, "Expected count 0, got %d\n", count);
|
||||
|
||||
ResetEvent(event);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
|
||||
|
||||
status = pNtSuspendThread(info.hThread, &count);
|
||||
ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status);
|
||||
ok(count == 0, "Expected count 0, got %d\n", count);
|
||||
|
||||
status = pNtSuspendThread(info.hThread, &count);
|
||||
ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status);
|
||||
ok(count == 1, "Expected count 1, got %d\n", count);
|
||||
|
||||
ResetEvent(event);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
|
||||
|
||||
ret = DebugActiveProcess(info.dwProcessId);
|
||||
ok(ret, "Failed to debug process: %d\n", GetLastError());
|
||||
|
||||
ResetEvent(event);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ret = WaitForDebugEvent(&ev, INFINITE);
|
||||
ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
|
||||
if (!ret) break;
|
||||
|
||||
if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) break;
|
||||
|
||||
ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
|
||||
ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
|
||||
if (!ret) break;
|
||||
}
|
||||
|
||||
ResetEvent(event);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
status = pNtResumeProcess(info.hProcess);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
status = NtResumeThread(info.hThread, &count);
|
||||
ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
|
||||
ok(count == 0, "Expected count 0, got %d\n", count);
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
|
||||
|
||||
ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
|
||||
ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
|
||||
|
||||
ret = WaitForSingleObject(event, 200);
|
||||
ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
|
||||
|
||||
TerminateProcess(info.hProcess, 0);
|
||||
|
||||
CloseHandle(info.hProcess);
|
||||
CloseHandle(info.hThread);
|
||||
}
|
||||
|
||||
static void dummy_process(char *event_name)
|
||||
{
|
||||
HANDLE event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
SetEvent(event);
|
||||
OutputDebugStringA("test");
|
||||
Sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(process)
|
||||
{
|
||||
HMODULE mod;
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
argc = winetest_get_mainargs(&argv);
|
||||
if (argc >= 4 && strcmp(argv[2], "dummy_process") == 0)
|
||||
{
|
||||
dummy_process(argv[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
mod = GetModuleHandleA("ntdll.dll");
|
||||
if (!mod)
|
||||
{
|
||||
win_skip("Not running on NT, skipping tests\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pNtResumeProcess = (void*)GetProcAddress(mod, "NtResumeProcess");
|
||||
pNtSuspendProcess = (void*)GetProcAddress(mod, "NtSuspendProcess");
|
||||
pNtResumeThread = (void*)GetProcAddress(mod, "NtResumeThread");
|
||||
pNtSuspendThread = (void*)GetProcAddress(mod, "NtSuspendThread");
|
||||
|
||||
test_NtSuspendProcess(argv[0]);
|
||||
}
|
||||
@@ -364,16 +364,22 @@ static void test_NtOpenKey(void)
|
||||
|
||||
/* Zero accessmask */
|
||||
attr.Length = sizeof(attr);
|
||||
key = (HANDLE)0xdeadbeef;
|
||||
status = pNtOpenKey(&key, 0, &attr);
|
||||
todo_wine
|
||||
ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
|
||||
todo_wine
|
||||
ok(!key, "key = %p\n", key);
|
||||
if (status == STATUS_SUCCESS) NtClose(key);
|
||||
|
||||
/* Calling without parent key requres full registry path. */
|
||||
pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
|
||||
InitializeObjectAttributes(&attr, &str, 0, 0, 0);
|
||||
key = (HANDLE)0xdeadbeef;
|
||||
status = pNtOpenKey(&key, KEY_READ, &attr);
|
||||
todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
|
||||
todo_wine
|
||||
ok(!key, "key = %p\n", key);
|
||||
pRtlFreeUnicodeString( &str );
|
||||
|
||||
/* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
|
||||
@@ -1070,8 +1076,10 @@ static void test_symlinks(void)
|
||||
/* try opening the target through the link */
|
||||
|
||||
attr.ObjectName = &link_str;
|
||||
key = (HANDLE)0xdeadbeef;
|
||||
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
||||
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
|
||||
ok( !key, "key = %p\n", key );
|
||||
|
||||
attr.ObjectName = &target_str;
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
@@ -1135,6 +1143,40 @@ static void test_symlinks(void)
|
||||
"wrong len %u\n", len );
|
||||
pNtClose( key );
|
||||
|
||||
if (pNtOpenKeyEx)
|
||||
{
|
||||
/* REG_OPTION_OPEN_LINK flag doesn't matter */
|
||||
status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
|
||||
|
||||
len = sizeof(buffer);
|
||||
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
|
||||
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
||||
"wrong len %u\n", len );
|
||||
pNtClose( key );
|
||||
|
||||
status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 );
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
|
||||
|
||||
len = sizeof(buffer);
|
||||
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
||||
ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
|
||||
ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
|
||||
"wrong len %u\n", len );
|
||||
pNtClose( key );
|
||||
|
||||
attr.Attributes = 0;
|
||||
status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
|
||||
|
||||
len = sizeof(buffer);
|
||||
status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
|
||||
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
|
||||
pNtClose( key );
|
||||
}
|
||||
|
||||
attr.Attributes = OBJ_OPENLINK;
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
|
||||
len = sizeof(buffer);
|
||||
@@ -1144,6 +1186,36 @@ static void test_symlinks(void)
|
||||
"wrong len %u\n", len );
|
||||
pNtClose( key );
|
||||
|
||||
/* delete target and create by NtCreateKey on link */
|
||||
attr.ObjectName = &target_str;
|
||||
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
|
||||
status = pNtDeleteKey( key );
|
||||
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
|
||||
pNtClose( key );
|
||||
|
||||
attr.ObjectName = &link_str;
|
||||
attr.Attributes = 0;
|
||||
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
||||
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
|
||||
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
|
||||
pNtClose( key );
|
||||
if (status) /* can be removed once todo_wine above is fixed */
|
||||
{
|
||||
attr.ObjectName = &target_str;
|
||||
attr.Attributes = OBJ_OPENLINK;
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
|
||||
pNtClose( key );
|
||||
}
|
||||
|
||||
attr.ObjectName = &target_str;
|
||||
attr.Attributes = OBJ_OPENLINK;
|
||||
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
|
||||
ok( status == STATUS_SUCCESS, "NtOpenKey wrong status 0x%08x\n", status );
|
||||
|
||||
if (0) /* crashes the Windows kernel on some Vista systems */
|
||||
{
|
||||
/* reopen the link from itself */
|
||||
@@ -1207,8 +1279,10 @@ static void test_symlinks(void)
|
||||
ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
|
||||
"NtOpenKey wrong status 0x%08x\n", status );
|
||||
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
|
||||
key = (HKEY)0xdeadbeef;
|
||||
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, NULL );
|
||||
ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
|
||||
ok( !key, "key = %p\n", key );
|
||||
|
||||
status = pNtDeleteKey( link );
|
||||
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
|
||||
|
||||
@@ -86,7 +86,6 @@ static RTL_HANDLE * (WINAPI * pRtlAllocateHandle)(RTL_HANDLE_TABLE *, ULONG *);
|
||||
static BOOLEAN (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *);
|
||||
static NTSTATUS (WINAPI *pRtlAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*);
|
||||
static NTSTATUS (WINAPI *pRtlFreeSid)(PSID);
|
||||
static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
|
||||
static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
|
||||
static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD);
|
||||
static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,USHORT*,INT_PTR);
|
||||
@@ -111,7 +110,10 @@ static NTSTATUS (WINAPI *pRtlCompressBuffer)(USHORT, const UCHAR*, ULONG, PUCHA
|
||||
static BOOL (WINAPI *pRtlIsCriticalSectionLocked)(CRITICAL_SECTION *);
|
||||
static BOOL (WINAPI *pRtlIsCriticalSectionLockedByThread)(CRITICAL_SECTION *);
|
||||
static NTSTATUS (WINAPI *pRtlInitializeCriticalSectionEx)(CRITICAL_SECTION *, ULONG, ULONG);
|
||||
static NTSTATUS (WINAPI *pLdrEnumerateLoadedModules)(void *, void *, void *);
|
||||
static NTSTATUS (WINAPI *pRtlQueryPackageIdentity)(HANDLE, WCHAR*, SIZE_T*, WCHAR*, SIZE_T*, BOOLEAN*);
|
||||
static NTSTATUS (WINAPI *pLdrRegisterDllNotification)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, void *, void **);
|
||||
static NTSTATUS (WINAPI *pLdrUnregisterDllNotification)(void *);
|
||||
|
||||
static HMODULE hkernel32 = 0;
|
||||
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
||||
@@ -119,6 +121,9 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
||||
|
||||
#define LEN 16
|
||||
static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */
|
||||
static WCHAR ws2_32dllW[] = {'w','s','2','_','3','2','.','d','l','l',0};
|
||||
static WCHAR wintrustdllW[] = {'w','i','n','t','r','u','s','t','.','d','l','l',0};
|
||||
static WCHAR crypt32dllW[] = {'c','r','y','p','t','3','2','.','d','l','l',0};
|
||||
static ULONG src_aligned_block[4];
|
||||
static ULONG dest_aligned_block[32];
|
||||
static const char *src = (const char*)src_aligned_block;
|
||||
@@ -149,7 +154,6 @@ static void InitFunctionPtrs(void)
|
||||
pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle");
|
||||
pRtlAllocateAndInitializeSid = (void *)GetProcAddress(hntdll, "RtlAllocateAndInitializeSid");
|
||||
pRtlFreeSid = (void *)GetProcAddress(hntdll, "RtlFreeSid");
|
||||
pNtCurrentTeb = (void *)GetProcAddress(hntdll, "NtCurrentTeb");
|
||||
pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode");
|
||||
pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode");
|
||||
pLdrProcessRelocationBlock = (void *)GetProcAddress(hntdll, "LdrProcessRelocationBlock");
|
||||
@@ -174,7 +178,10 @@ static void InitFunctionPtrs(void)
|
||||
pRtlIsCriticalSectionLocked = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLocked");
|
||||
pRtlIsCriticalSectionLockedByThread = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLockedByThread");
|
||||
pRtlInitializeCriticalSectionEx = (void *)GetProcAddress(hntdll, "RtlInitializeCriticalSectionEx");
|
||||
pLdrEnumerateLoadedModules = (void *)GetProcAddress(hntdll, "LdrEnumerateLoadedModules");
|
||||
pRtlQueryPackageIdentity = (void *)GetProcAddress(hntdll, "RtlQueryPackageIdentity");
|
||||
pLdrRegisterDllNotification = (void *)GetProcAddress(hntdll, "LdrRegisterDllNotification");
|
||||
pLdrUnregisterDllNotification = (void *)GetProcAddress(hntdll, "LdrUnregisterDllNotification");
|
||||
}
|
||||
hkernel32 = LoadLibraryA("kernel32.dll");
|
||||
ok(hkernel32 != 0, "LoadLibrary failed\n");
|
||||
@@ -382,8 +389,8 @@ static void test_RtlUlonglongByteSwap(void)
|
||||
|
||||
result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 );
|
||||
ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result,
|
||||
"RtlUlonglongByteSwap(0x7654321087654321) returns 0x%x%08x, expected 0x2143658710325476\n",
|
||||
(DWORD)(result >> 32), (DWORD)result);
|
||||
"RtlUlonglongByteSwap(0x7654321087654321) returns 0x%s, expected 0x2143658710325476\n",
|
||||
wine_dbgstr_longlong(result));
|
||||
}
|
||||
|
||||
|
||||
@@ -624,11 +631,11 @@ static void test_RtlUniform(void)
|
||||
seed_bak = seed;
|
||||
result = pRtlUniform(&seed);
|
||||
ok(result == expected,
|
||||
"test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
|
||||
(DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
|
||||
"test: 0x%s RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
|
||||
wine_dbgstr_longlong(num), seed_bak, result, expected);
|
||||
ok(seed == expected,
|
||||
"test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
|
||||
(DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
|
||||
"test: 0x%s RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
|
||||
wine_dbgstr_longlong(num), seed_bak, result, expected);
|
||||
} /* for */
|
||||
/*
|
||||
* Further investigation shows: In the different regions the highest bit
|
||||
@@ -671,11 +678,11 @@ static void test_RtlUniform(void)
|
||||
seed_bak = seed;
|
||||
result = pRtlUniform(&seed);
|
||||
ok(result == expected,
|
||||
"test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
|
||||
(DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
|
||||
"test: 0x%s RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
|
||||
wine_dbgstr_longlong(num), seed_bak, result, expected);
|
||||
ok(seed == expected,
|
||||
"test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
|
||||
(DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
|
||||
"test: 0x%s RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
|
||||
wine_dbgstr_longlong(num), seed_bak, result, expected);
|
||||
} /* for */
|
||||
/*
|
||||
* More tests show that RtlUniform does not return 0x7ffffffd for seed values
|
||||
@@ -919,10 +926,12 @@ static void test_RtlThreadErrorMode(void)
|
||||
mode, oldmode);
|
||||
ok(pRtlGetThreadErrorMode() == 0x70,
|
||||
"RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0x70);
|
||||
if (!is_wow64 && pNtCurrentTeb)
|
||||
ok(pNtCurrentTeb()->HardErrorDisabled == 0x70,
|
||||
if (!is_wow64)
|
||||
{
|
||||
ok(NtCurrentTeb()->HardErrorDisabled == 0x70,
|
||||
"The TEB contains 0x%x, expected 0x%x\n",
|
||||
pNtCurrentTeb()->HardErrorDisabled, 0x70);
|
||||
NtCurrentTeb()->HardErrorDisabled, 0x70);
|
||||
}
|
||||
|
||||
status = pRtlSetThreadErrorMode(0, &mode);
|
||||
ok(status == STATUS_SUCCESS ||
|
||||
@@ -933,10 +942,12 @@ static void test_RtlThreadErrorMode(void)
|
||||
mode, 0x70);
|
||||
ok(pRtlGetThreadErrorMode() == 0,
|
||||
"RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0);
|
||||
if (!is_wow64 && pNtCurrentTeb)
|
||||
ok(pNtCurrentTeb()->HardErrorDisabled == 0,
|
||||
if (!is_wow64)
|
||||
{
|
||||
ok(NtCurrentTeb()->HardErrorDisabled == 0,
|
||||
"The TEB contains 0x%x, expected 0x%x\n",
|
||||
pNtCurrentTeb()->HardErrorDisabled, 0);
|
||||
NtCurrentTeb()->HardErrorDisabled, 0);
|
||||
}
|
||||
|
||||
for (mode = 1; mode; mode <<= 1)
|
||||
{
|
||||
@@ -3158,6 +3169,119 @@ static void test_RtlInitializeCriticalSectionEx(void)
|
||||
RtlDeleteCriticalSection((PRTL_CRITICAL_SECTION)&cs);
|
||||
}
|
||||
|
||||
static void test_RtlLeaveCriticalSection(void)
|
||||
{
|
||||
RTL_CRITICAL_SECTION cs;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!pRtlInitializeCriticalSectionEx)
|
||||
return; /* Skip winxp */
|
||||
|
||||
status = RtlInitializeCriticalSection(&cs);
|
||||
ok(!status, "RtlInitializeCriticalSection failed: %x\n", status);
|
||||
|
||||
status = RtlEnterCriticalSection(&cs);
|
||||
ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
|
||||
todo_wine
|
||||
ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
|
||||
ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
|
||||
ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
|
||||
|
||||
status = RtlLeaveCriticalSection(&cs);
|
||||
ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
|
||||
ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
|
||||
ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
|
||||
ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
|
||||
|
||||
/*
|
||||
* Trying to leave a section that wasn't acquired modifies RecursionCount to an invalid value,
|
||||
* but doesn't modify LockCount so that an attempt to enter the section later will work.
|
||||
*/
|
||||
status = RtlLeaveCriticalSection(&cs);
|
||||
ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
|
||||
ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
|
||||
ok(cs.RecursionCount == -1, "expected RecursionCount == -1, got %d\n", cs.RecursionCount);
|
||||
ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
|
||||
|
||||
/* and again */
|
||||
status = RtlLeaveCriticalSection(&cs);
|
||||
ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
|
||||
ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
|
||||
ok(cs.RecursionCount == -2, "expected RecursionCount == -2, got %d\n", cs.RecursionCount);
|
||||
ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
|
||||
|
||||
/* entering section fixes RecursionCount */
|
||||
status = RtlEnterCriticalSection(&cs);
|
||||
ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
|
||||
todo_wine
|
||||
ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
|
||||
ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
|
||||
ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
|
||||
|
||||
status = RtlLeaveCriticalSection(&cs);
|
||||
ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
|
||||
ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
|
||||
ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
|
||||
ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
|
||||
|
||||
status = RtlDeleteCriticalSection(&cs);
|
||||
ok(!status, "RtlDeleteCriticalSection failed: %x\n", status);
|
||||
}
|
||||
|
||||
struct ldr_enum_context
|
||||
{
|
||||
BOOL abort;
|
||||
BOOL found;
|
||||
int count;
|
||||
};
|
||||
|
||||
static void WINAPI ldr_enum_callback(LDR_MODULE *module, void *context, BOOLEAN *stop)
|
||||
{
|
||||
static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
|
||||
struct ldr_enum_context *ctx = context;
|
||||
|
||||
if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW))
|
||||
ctx->found = TRUE;
|
||||
|
||||
ctx->count++;
|
||||
*stop = ctx->abort;
|
||||
}
|
||||
|
||||
static void test_LdrEnumerateLoadedModules(void)
|
||||
{
|
||||
struct ldr_enum_context ctx;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!pLdrEnumerateLoadedModules)
|
||||
{
|
||||
win_skip("LdrEnumerateLoadedModules not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.abort = FALSE;
|
||||
ctx.found = FALSE;
|
||||
ctx.count = 0;
|
||||
status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
|
||||
ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
|
||||
ok(ctx.count > 1, "Expected more than one module, got %d\n", ctx.count);
|
||||
ok(ctx.found, "Could not find ntdll in list of modules\n");
|
||||
|
||||
ctx.abort = TRUE;
|
||||
ctx.count = 0;
|
||||
status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
|
||||
ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
|
||||
ok(ctx.count == 1, "Expected exactly one module, got %d\n", ctx.count);
|
||||
|
||||
status = pLdrEnumerateLoadedModules((void *)0x1, ldr_enum_callback, (void *)0xdeadbeef);
|
||||
ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
|
||||
|
||||
status = pLdrEnumerateLoadedModules((void *)0xdeadbeef, ldr_enum_callback, (void *)0xdeadbeef);
|
||||
ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
|
||||
|
||||
status = pLdrEnumerateLoadedModules(NULL, NULL, (void *)0xdeadbeef);
|
||||
ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
|
||||
}
|
||||
|
||||
static void test_RtlQueryPackageIdentity(void)
|
||||
{
|
||||
const WCHAR programW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.',
|
||||
@@ -3228,6 +3352,248 @@ done:
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
static DWORD (CALLBACK *orig_entry)(HMODULE,DWORD,LPVOID);
|
||||
static DWORD *dll_main_data;
|
||||
|
||||
static inline void *get_rva( HMODULE module, DWORD va )
|
||||
{
|
||||
return (void *)((char *)module + va);
|
||||
}
|
||||
|
||||
static void CALLBACK ldr_notify_callback1(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
|
||||
{
|
||||
const IMAGE_IMPORT_DESCRIPTOR *imports;
|
||||
const IMAGE_THUNK_DATA *import_list;
|
||||
IMAGE_THUNK_DATA *thunk_list;
|
||||
DWORD *calls = context;
|
||||
LIST_ENTRY *mark;
|
||||
LDR_MODULE *mod;
|
||||
ULONG size;
|
||||
int i, j;
|
||||
|
||||
*calls <<= 4;
|
||||
*calls |= reason;
|
||||
|
||||
ok(data->Loaded.Flags == 0, "Expected flags 0, got %x\n", data->Loaded.Flags);
|
||||
ok(!lstrcmpiW(data->Loaded.BaseDllName->Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
|
||||
wine_dbgstr_w(data->Loaded.BaseDllName->Buffer));
|
||||
ok(!!data->Loaded.DllBase, "Expected non zero base address\n");
|
||||
ok(data->Loaded.SizeOfImage, "Expected non zero image size\n");
|
||||
|
||||
/* expect module to be last module listed in LdrData load order list */
|
||||
mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
|
||||
mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
|
||||
ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
|
||||
data->Loaded.DllBase, mod->BaseAddress);
|
||||
ok(!lstrcmpiW(mod->BaseDllName.Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
|
||||
wine_dbgstr_w(mod->BaseDllName.Buffer));
|
||||
|
||||
/* show that imports have already been resolved */
|
||||
imports = RtlImageDirectoryEntryToData(data->Loaded.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
|
||||
ok(!!imports, "Expected dll to have imports\n");
|
||||
|
||||
for (i = 0; imports[i].Name; i++)
|
||||
{
|
||||
thunk_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].FirstThunk);
|
||||
if (imports[i].OriginalFirstThunk)
|
||||
import_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].OriginalFirstThunk);
|
||||
else
|
||||
import_list = thunk_list;
|
||||
|
||||
for (j = 0; import_list[j].u1.Ordinal; j++)
|
||||
{
|
||||
ok(thunk_list[j].u1.AddressOfData > data->Loaded.SizeOfImage,
|
||||
"Import has not been resolved: %p\n", (void*)thunk_list[j].u1.Function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CALLBACK ldr_notify_callback2(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
|
||||
{
|
||||
DWORD *calls = context;
|
||||
*calls <<= 4;
|
||||
*calls |= reason + 2;
|
||||
}
|
||||
|
||||
static BOOL WINAPI fake_dll_main(HINSTANCE instance, DWORD reason, void* reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
*dll_main_data <<= 4;
|
||||
*dll_main_data |= 3;
|
||||
}
|
||||
else if (reason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
*dll_main_data <<= 4;
|
||||
*dll_main_data |= 4;
|
||||
}
|
||||
return orig_entry(instance, reason, reserved);
|
||||
}
|
||||
|
||||
static void CALLBACK ldr_notify_callback_dll_main(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
|
||||
{
|
||||
DWORD *calls = context;
|
||||
LIST_ENTRY *mark;
|
||||
LDR_MODULE *mod;
|
||||
|
||||
*calls <<= 4;
|
||||
*calls |= reason;
|
||||
|
||||
if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
|
||||
return;
|
||||
|
||||
mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
|
||||
mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
|
||||
ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
|
||||
data->Loaded.DllBase, mod->BaseAddress);
|
||||
if (mod->BaseAddress != data->Loaded.DllBase)
|
||||
return;
|
||||
|
||||
orig_entry = mod->EntryPoint;
|
||||
mod->EntryPoint = fake_dll_main;
|
||||
dll_main_data = calls;
|
||||
}
|
||||
|
||||
static BOOL WINAPI fake_dll_main_fail(HINSTANCE instance, DWORD reason, void* reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
*dll_main_data <<= 4;
|
||||
*dll_main_data |= 3;
|
||||
}
|
||||
else if (reason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
*dll_main_data <<= 4;
|
||||
*dll_main_data |= 4;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void CALLBACK ldr_notify_callback_fail(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
|
||||
{
|
||||
DWORD *calls = context;
|
||||
LIST_ENTRY *mark;
|
||||
LDR_MODULE *mod;
|
||||
|
||||
*calls <<= 4;
|
||||
*calls |= reason;
|
||||
|
||||
if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
|
||||
return;
|
||||
|
||||
mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
|
||||
mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
|
||||
ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
|
||||
data->Loaded.DllBase, mod->BaseAddress);
|
||||
if (mod->BaseAddress != data->Loaded.DllBase)
|
||||
return;
|
||||
|
||||
orig_entry = mod->EntryPoint;
|
||||
mod->EntryPoint = fake_dll_main_fail;
|
||||
dll_main_data = calls;
|
||||
}
|
||||
|
||||
static void CALLBACK ldr_notify_callback_imports(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
|
||||
{
|
||||
DWORD *calls = context;
|
||||
|
||||
if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
|
||||
return;
|
||||
|
||||
if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, crypt32dllW))
|
||||
{
|
||||
*calls <<= 4;
|
||||
*calls |= 1;
|
||||
}
|
||||
|
||||
if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, wintrustdllW))
|
||||
{
|
||||
*calls <<= 4;
|
||||
*calls |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_LdrRegisterDllNotification(void)
|
||||
{
|
||||
void *cookie, *cookie2;
|
||||
NTSTATUS status;
|
||||
HMODULE mod;
|
||||
DWORD calls;
|
||||
|
||||
if (!pLdrRegisterDllNotification || !pLdrUnregisterDllNotification)
|
||||
{
|
||||
win_skip("Ldr(Un)RegisterDllNotification not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* generic test */
|
||||
status = pLdrRegisterDllNotification(0, ldr_notify_callback1, &calls, &cookie);
|
||||
ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
calls = 0;
|
||||
mod = LoadLibraryW(ws2_32dllW);
|
||||
ok(!!mod, "Failed to load library: %d\n", GetLastError());
|
||||
ok(calls == LDR_DLL_NOTIFICATION_REASON_LOADED, "Expected LDR_DLL_NOTIFICATION_REASON_LOADED, got %x\n", calls);
|
||||
|
||||
calls = 0;
|
||||
FreeLibrary(mod);
|
||||
ok(calls == LDR_DLL_NOTIFICATION_REASON_UNLOADED, "Expected LDR_DLL_NOTIFICATION_REASON_UNLOADED, got %x\n", calls);
|
||||
|
||||
/* test order of callbacks */
|
||||
status = pLdrRegisterDllNotification(0, ldr_notify_callback2, &calls, &cookie2);
|
||||
ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
calls = 0;
|
||||
mod = LoadLibraryW(ws2_32dllW);
|
||||
ok(!!mod, "Failed to load library: %d\n", GetLastError());
|
||||
ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
|
||||
|
||||
calls = 0;
|
||||
FreeLibrary(mod);
|
||||
ok(calls == 0x24, "Expected order 0x24, got %x\n", calls);
|
||||
|
||||
pLdrUnregisterDllNotification(cookie2);
|
||||
pLdrUnregisterDllNotification(cookie);
|
||||
|
||||
/* test dll main order */
|
||||
status = pLdrRegisterDllNotification(0, ldr_notify_callback_dll_main, &calls, &cookie);
|
||||
ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
calls = 0;
|
||||
mod = LoadLibraryW(ws2_32dllW);
|
||||
ok(!!mod, "Failed to load library: %d\n", GetLastError());
|
||||
ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
|
||||
|
||||
calls = 0;
|
||||
FreeLibrary(mod);
|
||||
ok(calls == 0x42, "Expected order 0x42, got %x\n", calls);
|
||||
|
||||
pLdrUnregisterDllNotification(cookie);
|
||||
|
||||
/* test dll main order */
|
||||
status = pLdrRegisterDllNotification(0, ldr_notify_callback_fail, &calls, &cookie);
|
||||
ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
calls = 0;
|
||||
mod = LoadLibraryW(ws2_32dllW);
|
||||
ok(!mod, "Expected library to fail loading\n");
|
||||
ok(calls == 0x1342, "Expected order 0x1342, got %x\n", calls);
|
||||
|
||||
pLdrUnregisterDllNotification(cookie);
|
||||
|
||||
/* test dll with dependencies */
|
||||
status = pLdrRegisterDllNotification(0, ldr_notify_callback_imports, &calls, &cookie);
|
||||
ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
|
||||
|
||||
calls = 0;
|
||||
mod = LoadLibraryW(wintrustdllW);
|
||||
ok(!!mod, "Failed to load library: %d\n", GetLastError());
|
||||
ok(calls == 0x12, "Expected order 0x12, got %x\n", calls);
|
||||
|
||||
FreeLibrary(mod);
|
||||
pLdrUnregisterDllNotification(cookie);
|
||||
}
|
||||
|
||||
START_TEST(rtl)
|
||||
{
|
||||
InitFunctionPtrs();
|
||||
@@ -3264,5 +3630,8 @@ START_TEST(rtl)
|
||||
test_RtlDecompressBuffer();
|
||||
test_RtlIsCriticalSectionLocked();
|
||||
test_RtlInitializeCriticalSectionEx();
|
||||
test_RtlLeaveCriticalSection();
|
||||
test_LdrEnumerateLoadedModules();
|
||||
test_RtlQueryPackageIdentity();
|
||||
test_LdrRegisterDllNotification();
|
||||
}
|
||||
|
||||
@@ -425,15 +425,15 @@ static void test_RtlFindMostSignificantBit(void)
|
||||
ulLong <<= i;
|
||||
|
||||
cPos = pRtlFindMostSignificantBit(ulLong);
|
||||
ok (cPos == i, "didn't find MSB 0x%x%08x %d %d\n",
|
||||
(DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
|
||||
ok (cPos == i, "didn't find MSB 0x%s %d %d\n",
|
||||
wine_dbgstr_longlong(ulLong ), i, cPos);
|
||||
|
||||
/* Set all bits lower than bit i */
|
||||
ulLong = ((ulLong - 1) << 1) | 1;
|
||||
|
||||
cPos = pRtlFindMostSignificantBit(ulLong);
|
||||
ok (cPos == i, "didn't find MSB 0x%x%08x %d %d\n",
|
||||
(DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
|
||||
ok (cPos == i, "didn't find MSB 0x%s %d %d\n",
|
||||
wine_dbgstr_longlong(ulLong ), i, cPos);
|
||||
}
|
||||
cPos = pRtlFindMostSignificantBit(0);
|
||||
ok (cPos == -1, "found bit when not set\n");
|
||||
@@ -453,14 +453,14 @@ static void test_RtlFindLeastSignificantBit(void)
|
||||
ulLong = (ULONGLONG)1 << i;
|
||||
|
||||
cPos = pRtlFindLeastSignificantBit(ulLong);
|
||||
ok (cPos == i, "didn't find LSB 0x%x%08x %d %d\n",
|
||||
(DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
|
||||
ok (cPos == i, "didn't find LSB 0x%s %d %d\n",
|
||||
wine_dbgstr_longlong(ulLong ), i, cPos);
|
||||
|
||||
ulLong = ~((ULONGLONG)0) << i;
|
||||
|
||||
cPos = pRtlFindLeastSignificantBit(ulLong);
|
||||
ok (cPos == i, "didn't find LSB 0x%x%08x %d %d\n",
|
||||
(DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
|
||||
ok (cPos == i, "didn't find LSB 0x%s %d %d\n",
|
||||
wine_dbgstr_longlong(ulLong ), i, cPos);
|
||||
}
|
||||
cPos = pRtlFindLeastSignificantBit(0);
|
||||
ok (cPos == -1, "found bit when not set\n");
|
||||
|
||||
@@ -600,22 +600,21 @@ static void one_i64toa_test(int test_num, const ulonglong2str_t *ulonglong2str)
|
||||
dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0';
|
||||
result = p_i64toa(ulonglong2str->value, dest_str, ulonglong2str->base);
|
||||
ok(result == dest_str,
|
||||
"(test %d): _i64toa(%08x%08x, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
ulonglong2str->base, result, dest_str);
|
||||
"(test %d): _i64toa(%s, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value), ulonglong2str->base, result, dest_str);
|
||||
if (ulonglong2str->mask & 0x04) {
|
||||
if (memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) != 0) {
|
||||
if (memcmp(dest_str, ulonglong2str[1].Buffer, LARGE_STRI_BUFFER_LENGTH) != 0) {
|
||||
ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
|
||||
"(test %d): _i64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _i64toa(%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, dest_str, ulonglong2str->Buffer);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} else {
|
||||
ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
|
||||
"(test %d): _i64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _i64toa(%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, dest_str, ulonglong2str->Buffer);
|
||||
} /* if */
|
||||
}
|
||||
@@ -630,12 +629,11 @@ static void one_ui64toa_test(int test_num, const ulonglong2str_t *ulonglong2str)
|
||||
dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0';
|
||||
result = p_ui64toa(ulonglong2str->value, dest_str, ulonglong2str->base);
|
||||
ok(result == dest_str,
|
||||
"(test %d): _ui64toa(%08x%08x, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
ulonglong2str->base, result, dest_str);
|
||||
"(test %d): _ui64toa(%s, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value), ulonglong2str->base, result, dest_str);
|
||||
ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
|
||||
"(test %d): _ui64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _ui64toa(%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, dest_str, ulonglong2str->Buffer);
|
||||
}
|
||||
|
||||
@@ -682,9 +680,8 @@ static void one_i64tow_test(int test_num, const ulonglong2str_t *ulonglong2str)
|
||||
result = p_i64tow(ulonglong2str->value, dest_wstr, ulonglong2str->base);
|
||||
pRtlUnicodeStringToAnsiString(&ansi_str, &unicode_string, 1);
|
||||
ok(result == dest_wstr,
|
||||
"(test %d): _i64tow(0x%x%08x, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
ulonglong2str->base, result, dest_wstr);
|
||||
"(test %d): _i64tow(0x%s, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value), ulonglong2str->base, result, dest_wstr);
|
||||
if (ulonglong2str->mask & 0x04) {
|
||||
if (memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) != 0) {
|
||||
for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) {
|
||||
@@ -693,15 +690,15 @@ static void one_i64tow_test(int test_num, const ulonglong2str_t *ulonglong2str)
|
||||
expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0';
|
||||
if (memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) != 0) {
|
||||
ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
|
||||
"(test %d): _i64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _i64tow(0x%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} else {
|
||||
ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
|
||||
"(test %d): _i64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _i64tow(0x%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer);
|
||||
} /* if */
|
||||
pRtlFreeAnsiString(&ansi_str);
|
||||
@@ -733,12 +730,12 @@ static void one_ui64tow_test(int test_num, const ulonglong2str_t *ulonglong2str)
|
||||
result = p_ui64tow(ulonglong2str->value, dest_wstr, ulonglong2str->base);
|
||||
pRtlUnicodeStringToAnsiString(&ansi_str, &unicode_string, 1);
|
||||
ok(result == dest_wstr,
|
||||
"(test %d): _ui64tow(0x%x%08x, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _ui64tow(0x%s, [out], %d) has result %p, expected: %p\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, result, dest_wstr);
|
||||
ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
|
||||
"(test %d): _ui64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
|
||||
"(test %d): _ui64tow(0x%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
|
||||
test_num, wine_dbgstr_longlong(ulonglong2str->value),
|
||||
ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer);
|
||||
pRtlFreeAnsiString(&ansi_str);
|
||||
}
|
||||
@@ -764,8 +761,8 @@ static void test_ulonglongtow(void)
|
||||
/* Crashes on XP and W2K3 */
|
||||
result = p_i64tow(ulonglong2str[0].value, NULL, 10);
|
||||
ok(result == NULL,
|
||||
"(test d): _i64tow(0x%x%08x, NULL, 10) has result %p, expected: NULL\n",
|
||||
(DWORD)(ulonglong2str[0].value >> 32), (DWORD)ulonglong2str[0].value, result);
|
||||
"(test d): _i64tow(0x%s, NULL, 10) has result %p, expected: NULL\n",
|
||||
wine_dbgstr_longlong(ulonglong2str[0].value), result);
|
||||
}
|
||||
|
||||
if (p_ui64tow) {
|
||||
@@ -773,8 +770,8 @@ static void test_ulonglongtow(void)
|
||||
/* Crashes on XP and W2K3 */
|
||||
result = p_ui64tow(ulonglong2str[0].value, NULL, 10);
|
||||
ok(result == NULL,
|
||||
"(test e): _ui64tow(0x%x%08x, NULL, 10) has result %p, expected: NULL\n",
|
||||
(DWORD)(ulonglong2str[0].value >> 32), (DWORD)ulonglong2str[0].value, result);
|
||||
"(test e): _ui64tow(0x%s, NULL, 10) has result %p, expected: NULL\n",
|
||||
wine_dbgstr_longlong(ulonglong2str[0].value), result);
|
||||
}
|
||||
} /* if */
|
||||
}
|
||||
@@ -1085,14 +1082,14 @@ static void test_atoi64(void)
|
||||
ok(result == str2longlong[test_num].value ||
|
||||
(result == ((str2longlong[test_num].overflow == -1) ?
|
||||
ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff))),
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
|
||||
test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
|
||||
(DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
|
||||
test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
|
||||
wine_dbgstr_longlong(str2longlong[test_num].value));
|
||||
else
|
||||
ok(result == str2longlong[test_num].value,
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
|
||||
test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
|
||||
(DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
|
||||
test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
|
||||
wine_dbgstr_longlong(str2longlong[test_num].value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1110,14 +1107,14 @@ static void test_wtoi64(void)
|
||||
ok(result == str2longlong[test_num].value ||
|
||||
(result == ((str2longlong[test_num].overflow == -1) ?
|
||||
ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff))),
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
|
||||
test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
|
||||
(DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
|
||||
test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
|
||||
wine_dbgstr_longlong(str2longlong[test_num].value));
|
||||
else
|
||||
ok(result == str2longlong[test_num].value,
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
|
||||
test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
|
||||
(DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
|
||||
"(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
|
||||
test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
|
||||
wine_dbgstr_longlong(str2longlong[test_num].value));
|
||||
pRtlFreeUnicodeString(&uni);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ extern void func_om(void);
|
||||
extern void func_path(void);
|
||||
extern void func_pipe(void);
|
||||
extern void func_port(void);
|
||||
extern void func_process(void);
|
||||
extern void func_reg(void);
|
||||
extern void func_rtl(void);
|
||||
extern void func_rtlbitmap(void);
|
||||
@@ -42,6 +43,7 @@ const struct test winetest_testlist[] =
|
||||
{ "path", func_path },
|
||||
{ "pipe", func_pipe },
|
||||
{ "port", func_port },
|
||||
{ "process", func_process },
|
||||
{ "reg", func_reg },
|
||||
{ "rtl", func_rtl },
|
||||
{ "rtlbitmap", func_rtlbitmap },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,14 +18,88 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#include "ntdll_test.h"
|
||||
|
||||
/* FIXME: Inspect */
|
||||
|
||||
typedef struct _KSYSTEM_TIME {
|
||||
ULONG LowPart;
|
||||
LONG High1Time;
|
||||
LONG High2Time;
|
||||
} KSYSTEM_TIME, *PKSYSTEM_TIME;
|
||||
|
||||
typedef enum _NT_PRODUCT_TYPE {
|
||||
NtProductWinNt = 1,
|
||||
NtProductLanManNt,
|
||||
NtProductServer
|
||||
} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;
|
||||
|
||||
#define PROCESSOR_FEATURE_MAX 64
|
||||
|
||||
typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
|
||||
{
|
||||
StandardDesign,
|
||||
NEC98x86,
|
||||
EndAlternatives
|
||||
} ALTERNATIVE_ARCHITECTURE_TYPE;
|
||||
|
||||
#define MAX_WOW64_SHARED_ENTRIES 16
|
||||
|
||||
typedef struct _KUSER_SHARED_DATA {
|
||||
ULONG TickCountLowDeprecated;
|
||||
ULONG TickCountMultiplier;
|
||||
volatile KSYSTEM_TIME InterruptTime;
|
||||
volatile KSYSTEM_TIME SystemTime;
|
||||
volatile KSYSTEM_TIME TimeZoneBias;
|
||||
USHORT ImageNumberLow;
|
||||
USHORT ImageNumberHigh;
|
||||
WCHAR NtSystemRoot[260];
|
||||
ULONG MaxStackTraceDepth;
|
||||
ULONG CryptoExponent;
|
||||
ULONG TimeZoneId;
|
||||
ULONG LargePageMinimum;
|
||||
ULONG Reserved2[7];
|
||||
NT_PRODUCT_TYPE NtProductType;
|
||||
BOOLEAN ProductTypeIsValid;
|
||||
ULONG NtMajorVersion;
|
||||
ULONG NtMinorVersion;
|
||||
BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];
|
||||
ULONG Reserved1;
|
||||
ULONG Reserved3;
|
||||
volatile ULONG TimeSlip;
|
||||
ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
|
||||
LARGE_INTEGER SystemExpirationDate;
|
||||
ULONG SuiteMask;
|
||||
BOOLEAN KdDebuggerEnabled;
|
||||
UCHAR NXSupportPolicy;
|
||||
volatile ULONG ActiveConsoleId;
|
||||
volatile ULONG DismountCount;
|
||||
ULONG ComPlusPackage;
|
||||
ULONG LastSystemRITEventTickCount;
|
||||
ULONG NumberOfPhysicalPages;
|
||||
BOOLEAN SafeBootMode;
|
||||
ULONG TraceLogging;
|
||||
ULONGLONG TestRetInstruction;
|
||||
ULONG SystemCall;
|
||||
ULONG SystemCallReturn;
|
||||
ULONGLONG SystemCallPad[3];
|
||||
union {
|
||||
volatile KSYSTEM_TIME TickCount;
|
||||
volatile ULONG64 TickCountQuad;
|
||||
} DUMMYUNIONNAME;
|
||||
ULONG Cookie;
|
||||
ULONG Wow64SharedInformation[MAX_WOW64_SHARED_ENTRIES];
|
||||
} KSHARED_USER_DATA, *PKSHARED_USER_DATA;
|
||||
|
||||
#define TICKSPERSEC 10000000
|
||||
#define TICKSPERMSEC 10000
|
||||
#define SECSPERDAY 86400
|
||||
|
||||
static VOID (WINAPI *pRtlTimeToTimeFields)( const LARGE_INTEGER *liTime, PTIME_FIELDS TimeFields) ;
|
||||
static VOID (WINAPI *pRtlTimeFieldsToTime)( PTIME_FIELDS TimeFields, PLARGE_INTEGER Time) ;
|
||||
static NTSTATUS (WINAPI *pNtQueryPerformanceCounter)( LARGE_INTEGER *counter, LARGE_INTEGER *frequency );
|
||||
static ULONG (WINAPI *pNtGetTickCount)(void);
|
||||
|
||||
static const int MonthLengths[2][12] =
|
||||
{
|
||||
@@ -94,13 +168,60 @@ static void test_pRtlTimeToTimeFields(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_NtQueryPerformanceCounter(void)
|
||||
{
|
||||
LARGE_INTEGER counter, frequency;
|
||||
NTSTATUS status;
|
||||
|
||||
status = pNtQueryPerformanceCounter(NULL, NULL);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
|
||||
status = pNtQueryPerformanceCounter(NULL, &frequency);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
|
||||
status = pNtQueryPerformanceCounter(&counter, (void *)0xdeadbee0);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
|
||||
status = pNtQueryPerformanceCounter((void *)0xdeadbee0, &frequency);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
|
||||
|
||||
status = pNtQueryPerformanceCounter(&counter, NULL);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
status = pNtQueryPerformanceCounter(&counter, &frequency);
|
||||
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
|
||||
}
|
||||
|
||||
static void test_NtGetTickCount(void)
|
||||
{
|
||||
#ifndef _WIN64
|
||||
KSHARED_USER_DATA *user_shared_data = (void *)0x7ffe0000;
|
||||
LONG diff;
|
||||
int i;
|
||||
|
||||
if (!pNtGetTickCount)
|
||||
{
|
||||
win_skip("NtGetTickCount is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; ++i)
|
||||
{
|
||||
diff = (user_shared_data->u.TickCountQuad * user_shared_data->TickCountMultiplier) >> 24;
|
||||
diff = pNtGetTickCount() - diff;
|
||||
ok(diff < 32, "NtGetTickCount - TickCountQuad too high, expected < 32 got %d\n", diff);
|
||||
Sleep(50);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
START_TEST(time)
|
||||
{
|
||||
HMODULE mod = GetModuleHandleA("ntdll.dll");
|
||||
pRtlTimeToTimeFields = (void *)GetProcAddress(mod,"RtlTimeToTimeFields");
|
||||
pRtlTimeFieldsToTime = (void *)GetProcAddress(mod,"RtlTimeFieldsToTime");
|
||||
pNtQueryPerformanceCounter = (void *)GetProcAddress(mod, "NtQueryPerformanceCounter");
|
||||
pNtGetTickCount = (void *)GetProcAddress(mod,"NtGetTickCount");
|
||||
if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime)
|
||||
test_pRtlTimeToTimeFields();
|
||||
else
|
||||
win_skip("Required time conversion functions are not available\n");
|
||||
test_NtQueryPerformanceCounter();
|
||||
test_NtGetTickCount();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user