[NTDLL_WINETEST] Sync with Wine Staging 1.7.37. CORE-9246

svn path=/trunk/; revision=66658
This commit is contained in:
Amine Khaldi 2015-03-10 10:10:04 +00:00
parent 6bd29991d4
commit 26326ca7d5
8 changed files with 1560 additions and 47 deletions

View file

@ -51,7 +51,6 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG *
/* The attribute sets to test */
static struct testfile_s {
BOOL todo; /* set if it doesn't work on wine yet */
BOOL attr_done; /* set if attributes were tested for this file already */
const DWORD attr; /* desired attribute */
const char *name; /* filename to use */
@ -60,13 +59,13 @@ static struct testfile_s {
int nfound; /* How many were found (expect 1) */
WCHAR nameW[20]; /* unicode version of name (filled in later) */
} testfiles[] = {
{ 0, 0, FILE_ATTRIBUTE_NORMAL, "n.tmp", NULL, "normal" },
{ 1, 0, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" },
{ 1, 0, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" },
{ 0, 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" },
{ 0, 0, FILE_ATTRIBUTE_DIRECTORY, ".", NULL, ". directory" },
{ 0, 0, FILE_ATTRIBUTE_DIRECTORY, "..", NULL, ".. directory" },
{ 0, 0, 0, NULL }
{ 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 }
};
static const int max_test_dir_size = 20; /* size of above plus some for .. etc */
@ -147,12 +146,7 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info)
if (namelen != len || memcmp(nameW, testfiles[i].nameW, len*sizeof(WCHAR)))
continue;
if (!testfiles[i].attr_done) {
if (testfiles[i].todo) {
todo_wine
ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib);
} else {
ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib);
}
ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles[i].name, testfiles[i].description, testfiles[i].attr, attrib);
testfiles[i].attr_done = TRUE;
}
testfiles[i].nfound++;

View file

@ -46,11 +46,14 @@ static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
static PVOID (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID);
static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler);
static PVOID (WINAPI *pRtlAddVectoredContinueHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func);
static ULONG (WINAPI *pRtlRemoveVectoredContinueHandler)(PVOID handler);
static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*);
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static NTSTATUS (WINAPI *pNtClose)(HANDLE);
#if defined(__x86_64__)
static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
@ -936,6 +939,16 @@ static void test_debugger(void)
/* here we handle exception */
}
}
else if (stage == 7 || stage == 8)
{
ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE,
"unexpected exception code %08x, expected %08x\n", de.u.Exception.ExceptionRecord.ExceptionCode,
EXCEPTION_INVALID_HANDLE);
ok(de.u.Exception.ExceptionRecord.NumberParameters == 0,
"unexpected number of parameters %d, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters);
if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
}
else
ok(FALSE, "unexpected stage %x\n", stage);
@ -1695,6 +1708,7 @@ static void test_dynamic_unwind(void)
#endif /* __x86_64__ */
#if defined(__i386__) || defined(__x86_64__)
static DWORD outputdebugstring_exceptions;
static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
@ -1713,7 +1727,7 @@ static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *Exce
return EXCEPTION_CONTINUE_SEARCH;
}
static void test_outputdebugstring(DWORD numexc, BOOL todo)
static void test_outputdebugstring(DWORD numexc)
{
PVOID vectored_handler;
@ -1728,13 +1742,8 @@ static void test_outputdebugstring(DWORD numexc, BOOL todo)
outputdebugstring_exceptions = 0;
OutputDebugStringA("Hello World");
if (todo)
todo_wine
ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
outputdebugstring_exceptions, numexc);
else
ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
outputdebugstring_exceptions, numexc);
ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
outputdebugstring_exceptions, numexc);
pRtlRemoveVectoredExceptionHandler(vectored_handler);
}
@ -1788,6 +1797,91 @@ static void test_ripevent(DWORD numexc)
pRtlRemoveVectoredExceptionHandler(vectored_handler);
}
static DWORD invalid_handle_exceptions;
static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
{
PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
trace("vect. handler %08x addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress);
ok(rec->ExceptionCode == EXCEPTION_INVALID_HANDLE, "ExceptionCode is %08x instead of %08x\n",
rec->ExceptionCode, EXCEPTION_INVALID_HANDLE);
ok(rec->NumberParameters == 0, "ExceptionParameters is %d instead of 0\n", rec->NumberParameters);
invalid_handle_exceptions++;
return (rec->ExceptionCode == EXCEPTION_INVALID_HANDLE) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
static void test_closehandle(DWORD numexc)
{
PVOID vectored_handler;
NTSTATUS status;
DWORD res;
if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler || !pRtlRaiseException)
{
skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler or RtlRaiseException not found\n");
return;
}
vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &invalid_handle_vectored_handler);
ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
invalid_handle_exceptions = 0;
res = CloseHandle((HANDLE)0xdeadbeef);
ok(!res, "CloseHandle(0xdeadbeef) unexpectedly succeeded\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error code %d instead of %d",
GetLastError(), ERROR_INVALID_HANDLE);
ok(invalid_handle_exceptions == numexc, "CloseHandle generated %d exceptions, expected %d\n",
invalid_handle_exceptions, numexc);
invalid_handle_exceptions = 0;
status = pNtClose((HANDLE)0xdeadbeef);
ok(status == STATUS_INVALID_HANDLE, "NtClose(0xdeadbeef) returned status %08x\n", status);
ok(invalid_handle_exceptions == numexc, "NtClose generated %d exceptions, expected %d\n",
invalid_handle_exceptions, numexc);
pRtlRemoveVectoredExceptionHandler(vectored_handler);
}
static void test_vectored_continue_handler(void)
{
PVOID handler1, handler2;
ULONG ret;
if (!pRtlAddVectoredContinueHandler || !pRtlRemoveVectoredContinueHandler)
{
skip("RtlAddVectoredContinueHandler or RtlRemoveVectoredContinueHandler not found\n");
return;
}
handler1 = pRtlAddVectoredContinueHandler(TRUE, (void *)0xdeadbeef);
ok(handler1 != 0, "RtlAddVectoredContinueHandler failed\n");
handler2 = pRtlAddVectoredContinueHandler(TRUE, (void *)0xdeadbeef);
ok(handler2 != 0, "RtlAddVectoredContinueHandler failed\n");
ok(handler1 != handler2, "RtlAddVectoredContinueHandler returned same handler\n");
if (pRtlRemoveVectoredExceptionHandler)
{
ret = pRtlRemoveVectoredExceptionHandler(handler1);
ok(!ret, "RtlRemoveVectoredExceptionHandler succeeded\n");
}
ret = pRtlRemoveVectoredContinueHandler(handler1);
ok(ret, "RtlRemoveVectoredContinueHandler failed\n");
ret = pRtlRemoveVectoredContinueHandler(handler2);
ok(ret, "RtlRemoveVectoredContinueHandler failed\n");
ret = pRtlRemoveVectoredContinueHandler(handler1);
ok(!ret, "RtlRemoveVectoredContinueHandler succeeded\n");
ret = pRtlRemoveVectoredContinueHandler((void *)0x11223344);
ok(!ret, "RtlRemoveVectoredContinueHandler succeeded\n");
}
#endif /* defined(__i386__) || defined(__x86_64__) */
START_TEST(exception)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@ -1802,6 +1896,7 @@ START_TEST(exception)
pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread" );
pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread" );
pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" );
pNtClose = (void *)GetProcAddress( hntdll, "NtClose" );
pRtlUnwind = (void *)GetProcAddress( hntdll, "RtlUnwind" );
pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException" );
pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess" );
@ -1809,6 +1904,10 @@ START_TEST(exception)
"RtlAddVectoredExceptionHandler" );
pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
"RtlRemoveVectoredExceptionHandler" );
pRtlAddVectoredContinueHandler = (void *)GetProcAddress( hntdll,
"RtlAddVectoredContinueHandler" );
pRtlRemoveVectoredContinueHandler = (void *)GetProcAddress( hntdll,
"RtlRemoveVectoredContinueHandler" );
pNtQueryInformationProcess = (void*)GetProcAddress( hntdll,
"NtQueryInformationProcess" );
pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
@ -1858,13 +1957,17 @@ START_TEST(exception)
run_rtlraiseexception_test(EXCEPTION_BREAKPOINT);
run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE);
test_stage = 3;
test_outputdebugstring(0, FALSE);
test_outputdebugstring(0);
test_stage = 4;
test_outputdebugstring(2, TRUE); /* is this a Windows bug? */
test_outputdebugstring(2);
test_stage = 5;
test_ripevent(0);
test_stage = 6;
test_ripevent(1);
test_stage = 7;
test_closehandle(0);
test_stage = 8;
test_closehandle(1);
}
else
skip( "RtlRaiseException not found\n" );
@ -1876,8 +1979,10 @@ START_TEST(exception)
test_unwind();
test_exceptions();
test_rtlraiseexception();
test_outputdebugstring(1, FALSE);
test_outputdebugstring(1);
test_ripevent(1);
test_closehandle(0);
test_vectored_continue_handler();
test_debugger();
test_simd_exceptions();
test_fpu_exceptions();
@ -1894,8 +1999,10 @@ START_TEST(exception)
pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
"RtlLookupFunctionEntry" );
test_outputdebugstring(1, FALSE);
test_outputdebugstring(1);
test_ripevent(1);
test_closehandle(0);
test_vectored_continue_handler();
test_virtual_unwind();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)

View file

@ -38,6 +38,33 @@
#include "winuser.h"
#include "wine/winioctl.h"
/* FIXME */
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
_ANONYMOUS_UNION union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
#ifndef IO_COMPLETION_ALL_ACCESS
#define IO_COMPLETION_ALL_ACCESS 0x001F0003
#endif
@ -1234,7 +1261,7 @@ static void test_file_basic_information(void)
memset(&fbi, 0, sizeof(fbi));
res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes );
ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fbi.FileAttributes );
/* Then HIDDEN */
memset(&fbi, 0, sizeof(fbi));
@ -1247,7 +1274,7 @@ static void test_file_basic_information(void)
memset(&fbi, 0, sizeof(fbi));
res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes );
ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fbi.FileAttributes );
/* Check NORMAL last of all (to make sure we can clear attributes) */
memset(&fbi, 0, sizeof(fbi));
@ -1304,7 +1331,7 @@ static void test_file_all_information(void)
memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res);
todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes );
ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes );
/* Then HIDDEN */
memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
@ -1317,7 +1344,7 @@ static void test_file_all_information(void)
memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes );
ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes );
/* Check NORMAL last of all (to make sure we can clear attributes) */
memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
@ -1371,7 +1398,6 @@ static void test_file_disposition_information(void)
ok( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "Unexpected NtQueryInformationFile result (expected STATUS_INVALID_INFO_CLASS, got %x)\n", res );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_ACCESS_DENIED, "unexpected FileDispositionInformation result (expected STATUS_ACCESS_DENIED, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -1384,14 +1410,26 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
todo_wine
ok( fileDeleted, "File should have been deleted\n" );
DeleteFileA( buffer );
/* cannot set disposition on readonly file */
GetTempFileNameA( tmp_path, "dis", 0, buffer );
DeleteFileA( buffer );
handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "File shouldn't have been deleted\n" );
SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
DeleteFileA( buffer );
/* cannot set disposition on readonly file */
GetTempFileNameA( tmp_path, "dis", 0, buffer );
handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
@ -1402,6 +1440,21 @@ static void test_file_disposition_information(void)
ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
todo_wine
ok( !fileDeleted, "File shouldn't have been deleted\n" );
SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
DeleteFileA( buffer );
/* cannot set disposition on readonly file */
GetTempFileNameA( tmp_path, "dis", 0, buffer );
DeleteFileA( buffer );
handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0);
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
ok( res == STATUS_CANNOT_DELETE, "unexpected FileDispositionInformation result (expected STATUS_CANNOT_DELETE, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "File shouldn't have been deleted\n" );
SetFileAttributesA( buffer, FILE_ATTRIBUTE_NORMAL );
DeleteFileA( buffer );
@ -1412,11 +1465,9 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -1429,7 +1480,6 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -1444,7 +1494,6 @@ static void test_file_disposition_information(void)
CloseHandle( handle );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle2, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle2 );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -1459,11 +1508,9 @@ static void test_file_disposition_information(void)
ok( handle != INVALID_HANDLE_VALUE, "failed to open a directory\n" );
fdi.DoDeleteFile = TRUE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
todo_wine
ok( fileDeleted, "Directory should have been deleted\n" );
RemoveDirectoryA( buffer );
@ -1476,7 +1523,6 @@ static void test_file_disposition_information(void)
RemoveDirectoryA( buffer );
fdi.DoDeleteFile = FALSE;
res = pNtSetInformationFile( handle, &io, &fdi, sizeof fdi, FileDispositionInformation );
todo_wine
ok( res == STATUS_SUCCESS, "unexpected FileDispositionInformation result (expected STATUS_SUCCESS, got %x)\n", res );
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -1501,6 +1547,7 @@ static void test_file_disposition_information(void)
buffer[dirpos] = '\0';
CloseHandle( handle );
fileDeleted = GetFileAttributesA( buffer ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
todo_wine
ok( !fileDeleted, "Directory shouldn't have been deleted\n" );
RemoveDirectoryA( buffer );
}
@ -2683,6 +2730,178 @@ todo_wine
CloseHandle(hfile);
}
static INT build_reparse_buffer(WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer)
{
REPARSE_DATA_BUFFER *buffer;
INT buffer_len, string_len;
WCHAR *dest;
string_len = (lstrlenW(filename)+1)*sizeof(WCHAR);
buffer_len = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[1]) + string_len;
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
buffer->ReparseDataLength = sizeof(buffer->MountPointReparseBuffer) + string_len;
buffer->MountPointReparseBuffer.SubstituteNameLength = string_len - sizeof(WCHAR);
buffer->MountPointReparseBuffer.PrintNameOffset = string_len;
dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
memcpy(dest, filename, string_len);
*pbuffer = buffer;
return buffer_len;
}
static void test_junction_points(void)
{
static const WCHAR junctionW[] = {'\\','j','u','n','c','t','i','o','n',0};
WCHAR path[MAX_PATH], junction_path[MAX_PATH], target_path[MAX_PATH];
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
FILE_BASIC_INFORMATION old_attrib, new_attrib;
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
INT buffer_len, string_len;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
HANDLE hJunction;
WCHAR *dest;
BOOL bret;
/* Create a temporary folder for the junction point tests */
GetTempFileNameW(dotW, fooW, 0, path);
DeleteFileW(path);
if (!CreateDirectoryW(path, NULL))
{
win_skip("Unable to create a temporary junction point directory.\n");
return;
}
/* Check that the volume this folder is located on supports junction points */
pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
volW[0] = nameW.Buffer[4];
pRtlFreeUnicodeString( &nameW );
GetVolumeInformationW(volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0);
if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
{
skip("File system does not support junction points.\n");
RemoveDirectoryW(path);
return;
}
/* Create the folder to be replaced by a junction point */
lstrcpyW(junction_path, path);
lstrcatW(junction_path, junctionW);
bret = CreateDirectoryW(junction_path, NULL);
ok(bret, "Failed to create junction point directory.\n");
/* Create a destination folder for the junction point to target */
lstrcpyW(target_path, path);
lstrcatW(target_path, targetW);
bret = CreateDirectoryW(target_path, NULL);
ok(bret, "Failed to create junction point target directory.\n");
pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL);
/* Create the junction point */
hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
if (hJunction == INVALID_HANDLE_VALUE)
{
win_skip("Failed to open junction point directory handle (0x%x).\n", GetLastError());
goto cleanup;
}
dwret = NtQueryInformationFile(hJunction, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
/* Check the file attributes of the junction point */
dwret = GetFileAttributesW(junction_path);
ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: %d)\n", dwret);
/* Read back the junction point */
HeapFree(GetProcessHeap(), 0, buffer);
buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
bret = DeviceIoControl(hJunction, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
ok(bret, "Failed to read junction point!\n");
ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n",
wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
/* Delete the junction point */
memset(&old_attrib, 0x00, sizeof(old_attrib));
old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef;
dwret = NtSetInformationFile(hJunction, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to set junction point folder's attributes (0x%x).\n", dwret);
memset(&guid_buffer, 0x00, sizeof(guid_buffer));
guid_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
bret = DeviceIoControl(hJunction, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer,
REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0);
ok(bret, "Failed to delete junction point! (0x%x)\n", GetLastError());
memset(&new_attrib, 0x00, sizeof(new_attrib));
dwret = NtQueryInformationFile(hJunction, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart,
"Junction point folder's access time does not match (0x%llx != 0x%llx).\n",
new_attrib.LastAccessTime.QuadPart, old_attrib.LastAccessTime.QuadPart);
CloseHandle(hJunction);
/* Check deleting a junction point as if it were a directory */
HeapFree(GetProcessHeap(), 0, buffer);
hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(hJunction);
bret = RemoveDirectoryW(junction_path);
ok(bret, "Failed to delete junction point as directory!\n");
dwret = GetFileAttributesW(junction_path);
ok(dwret == (DWORD)~0, "Junction point still exists (attributes: 0x%x)!\n", dwret);
/* Check deleting a junction point as if it were a file */
HeapFree(GetProcessHeap(), 0, buffer);
bret = CreateDirectoryW(junction_path, NULL);
ok(bret, "Failed to create junction point target directory.\n");
hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(hJunction);
bret = DeleteFileW(junction_path);
ok(!bret, "Succeeded in deleting junction point as file!\n");
err = GetLastError();
ok(err == ERROR_ACCESS_DENIED, "Expected last error 0x%x for DeleteFile on junction point (actually 0x%x)!\n",
ERROR_ACCESS_DENIED, err);
dwret = GetFileAttributesW(junction_path);
ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%x)\n", dwret);
/* Test deleting a junction point's target */
dwret = GetFileAttributesW(junction_path);
ok(dwret == 0x410 || broken(dwret == 0x430) /* win2k */,
"Unexpected junction point attributes (0x%x != 0x410)!\n", dwret);
bret = RemoveDirectoryW(target_path);
ok(bret, "Failed to delete junction point target!\n");
bret = CreateDirectoryW(target_path, NULL);
ok(bret, "Failed to create junction point target directory.\n");
cleanup:
/* Cleanup */
pRtlFreeUnicodeString( &nameW );
HeapFree(GetProcessHeap(), 0, buffer);
bret = RemoveDirectoryW(junction_path);
ok(bret, "Failed to remove temporary junction point directory!\n");
bret = RemoveDirectoryW(target_path);
ok(bret, "Failed to remove temporary target directory!\n");
RemoveDirectoryW(path);
}
START_TEST(file)
{
HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
@ -2736,4 +2955,5 @@ START_TEST(file)
test_file_disposition_information();
test_query_volume_information_file();
test_query_attribute_information_file();
test_junction_points();
}

View file

@ -737,6 +737,84 @@ static void test_query_processor_power_info(void)
HeapFree(GetProcessHeap(), 0, ppi);
}
static void test_query_process_wow64(void)
{
NTSTATUS status;
ULONG ReturnLength;
ULONG_PTR pbi[2], dummy;
memset(&dummy, 0xcc, sizeof(dummy));
/* Do not give a handle and buffer */
status = pNtQueryInformationProcess(NULL, ProcessWow64Information, NULL, 0, NULL);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
/* Use a correct info class and buffer size, but still no handle and buffer */
status = pNtQueryInformationProcess(NULL, ProcessWow64Information, NULL, sizeof(ULONG_PTR), NULL);
ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
"Expected STATUS_ACCESS_VIOLATION or STATUS_INVALID_HANDLE, got %08x\n", status);
/* Use a correct info class, buffer size and handle, but no buffer */
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, NULL, sizeof(ULONG_PTR), NULL);
ok( status == STATUS_ACCESS_VIOLATION , "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
/* Use a correct info class, buffer and buffer size, but no handle */
pbi[0] = pbi[1] = dummy;
status = pNtQueryInformationProcess(NULL, ProcessWow64Information, pbi, sizeof(ULONG_PTR), NULL);
ok( status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got %08x\n", status);
ok( pbi[0] == dummy, "pbi[0] changed to %lx\n", pbi[0]);
ok( pbi[1] == dummy, "pbi[1] changed to %lx\n", pbi[1]);
/* Use a greater buffer size */
pbi[0] = pbi[1] = dummy;
status = pNtQueryInformationProcess(NULL, ProcessWow64Information, pbi, sizeof(ULONG_PTR) + 1, NULL);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
ok( pbi[0] == dummy, "pbi[0] changed to %lx\n", pbi[0]);
ok( pbi[1] == dummy, "pbi[1] changed to %lx\n", pbi[1]);
/* Use no ReturnLength */
pbi[0] = pbi[1] = dummy;
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, pbi, sizeof(ULONG_PTR), NULL);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
trace( "Platform is_wow64 %d, ProcessInformation of ProcessWow64Information %lx\n", is_wow64, pbi[0]);
ok( is_wow64 == (pbi[0] != 0), "is_wow64 %x, pbi[0] %lx\n", is_wow64, pbi[0]);
ok( pbi[0] != dummy, "pbi[0] %lx\n", pbi[0]);
ok( pbi[1] == dummy, "pbi[1] changed to %lx\n", pbi[1]);
/* Test written size on 64 bit by checking high 32 bit buffer */
if (sizeof(ULONG_PTR) > sizeof(DWORD))
{
DWORD *ptr = (DWORD *)pbi;
ok( ptr[1] != (DWORD)dummy, "ptr[1] unchanged!\n");
}
/* Finally some correct calls */
pbi[0] = pbi[1] = dummy;
ReturnLength = 0xdeadbeef;
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, pbi, sizeof(ULONG_PTR), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
ok( is_wow64 == (pbi[0] != 0), "is_wow64 %x, pbi[0] %lx\n", is_wow64, pbi[0]);
ok( pbi[1] == dummy, "pbi[1] changed to %lx\n", pbi[1]);
ok( ReturnLength == sizeof(ULONG_PTR), "Inconsistent length %d\n", ReturnLength);
/* Everything is correct except a too small buffer size */
pbi[0] = pbi[1] = dummy;
ReturnLength = 0xdeadbeef;
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, pbi, sizeof(ULONG_PTR) - 1, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
ok( pbi[0] == dummy, "pbi[0] changed to %lx\n", pbi[0]);
ok( pbi[1] == dummy, "pbi[1] changed to %lx\n", pbi[1]);
todo_wine ok( ReturnLength == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", ReturnLength);
/* Everything is correct except a too large buffer size */
pbi[0] = pbi[1] = dummy;
ReturnLength = 0xdeadbeef;
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessWow64Information, pbi, sizeof(ULONG_PTR) + 1, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
ok( pbi[0] == dummy, "pbi[0] changed to %lx\n", pbi[0]);
ok( pbi[1] == dummy, "pbi[1] changed to %lx\n", pbi[1]);
todo_wine ok( ReturnLength == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", ReturnLength);
}
static void test_query_process_basic(void)
{
NTSTATUS status;
@ -1714,6 +1792,10 @@ START_TEST(info)
trace("Starting test_query_process_handlecount()\n");
test_query_process_handlecount();
/* 0x1A ProcessWow64Information */
trace("Starting test_query_process_wow64()\n");
test_query_process_wow64();
/* 0x1B ProcessImageFileName */
trace("Starting test_query_process_image_file_name()\n");
test_query_process_image_file_name();

View file

@ -835,14 +835,14 @@ static void test_event(void)
status = pNtOpenEvent(&Event2, GENERIC_ALL, &attr);
ok( status == STATUS_SUCCESS, "NtOpenEvent failed %08x\n", status );
status = pNtClose(Event);
pNtClose(Event);
status = pNtQueryEvent(Event2, EventBasicInformation, &info, sizeof(info), NULL);
ok( status == STATUS_SUCCESS, "NtQueryEvent failed %08x\n", status );
ok( info.EventType == 1 && info.EventState == 0,
"NtQueryEvent failed, expected 1 0, got %d %d\n", info.EventType, info.EventState );
status = pNtClose(Event2);
pNtClose(Event2);
}
static const WCHAR keyed_nameW[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',

View file

@ -129,11 +129,14 @@ static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
static NTSTATUS (WINAPI * pNtCreateKey)( PHANDLE retkey, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
ULONG TitleIndex, const UNICODE_STRING *class, ULONG options,
PULONG dispos );
static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,KEY_INFORMATION_CLASS,PVOID,ULONG,PULONG);
static NTSTATUS (WINAPI * pNtQueryLicenseValue)(const UNICODE_STRING *,ULONG *,PVOID,ULONG,ULONG *);
static NTSTATUS (WINAPI * pNtQueryValueKey)(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
static NTSTATUS (WINAPI * pNtSetValueKey)(HANDLE, const PUNICODE_STRING, ULONG,
ULONG, const void*, ULONG );
static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(PUNICODE_STRING);
static LONG (WINAPI * pRtlCompareUnicodeString)(const PUNICODE_STRING,const PUNICODE_STRING,BOOLEAN);
static BOOLEAN (WINAPI * pRtlCreateUnicodeString)(PUNICODE_STRING, LPCWSTR);
static LPVOID (WINAPI * pRtlReAllocateHeap)(IN PVOID, IN ULONG, IN PVOID, IN ULONG);
static NTSTATUS (WINAPI * pRtlAppendUnicodeToString)(PUNICODE_STRING, PCWSTR);
@ -166,7 +169,6 @@ static BOOL InitFunctionPtrs(void)
NTDLL_GET_PROC(RtlCreateUnicodeStringFromAsciiz)
NTDLL_GET_PROC(RtlCreateUnicodeString)
NTDLL_GET_PROC(RtlFreeUnicodeString)
NTDLL_GET_PROC(NtDeleteValueKey)
NTDLL_GET_PROC(RtlQueryRegistryValues)
NTDLL_GET_PROC(RtlCheckRegistryKey)
NTDLL_GET_PROC(RtlOpenCurrentUser)
@ -175,11 +177,13 @@ static BOOL InitFunctionPtrs(void)
NTDLL_GET_PROC(NtCreateKey)
NTDLL_GET_PROC(NtFlushKey)
NTDLL_GET_PROC(NtDeleteKey)
NTDLL_GET_PROC(NtQueryKey)
NTDLL_GET_PROC(NtQueryValueKey)
NTDLL_GET_PROC(NtQueryInformationProcess)
NTDLL_GET_PROC(NtSetValueKey)
NTDLL_GET_PROC(NtOpenKey)
NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath)
NTDLL_GET_PROC(RtlCompareUnicodeString)
NTDLL_GET_PROC(RtlReAllocateHeap)
NTDLL_GET_PROC(RtlAppendUnicodeToString)
NTDLL_GET_PROC(RtlUnicodeStringToAnsiString)
@ -188,6 +192,10 @@ static BOOL InitFunctionPtrs(void)
NTDLL_GET_PROC(RtlZeroMemory)
NTDLL_GET_PROC(RtlpNtQueryValueKey)
NTDLL_GET_PROC(RtlOpenCurrentUser)
/* optional functions */
pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue");
return TRUE;
}
#undef NTDLL_GET_PROC
@ -642,6 +650,180 @@ static void test_NtDeleteKey(void)
ok(status == STATUS_SUCCESS, "NtDeleteKey Failed: 0x%08x\n", status);
}
static void test_NtQueryLicenseKey(void)
{
static const WCHAR emptyW[] = {'E','M','P','T','Y',0};
UNICODE_STRING name;
WORD buffer[32];
NTSTATUS status;
ULONG type, len;
DWORD value;
if (!pNtQueryLicenseValue)
{
win_skip("NtQueryLicenseValue not found, skipping tests\n");
return;
}
type = 0xdead;
len = 0xbeef;
memset(&name, 0, sizeof(name));
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
/* test with empty key */
pRtlCreateUnicodeStringFromAsciiz(&name, "");
type = 0xdead;
len = 0xbeef;
status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
type = 0xdead;
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
len = 0xbeef;
status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
type = 0xdead;
len = 0xbeef;
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
pRtlFreeUnicodeString(&name);
/* test with nonexistent licence key */
pRtlCreateUnicodeStringFromAsciiz(&name, "Nonexistent-License-Value");
type = 0xdead;
len = 0xbeef;
status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
type = 0xdead;
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
len = 0xbeef;
status = pNtQueryLicenseValue(&name, NULL, buffer, sizeof(buffer), &len);
ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue returned %08x, expected STATUS_OBJECT_NAME_NOT_FOUND\n", status);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
type = 0xdead;
len = 0xbeef;
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryLicenseValue unexpected suceeded\n");
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
pRtlFreeUnicodeString(&name);
/* test with REG_SZ license key */
pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Language-Allowed");
type = 0xdead;
len = 0xbeef;
status = pNtQueryLicenseValue(NULL, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
type = 0xdead;
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), NULL);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
type = 0xdead;
len = 0;
status = pNtQueryLicenseValue(&name, &type, buffer, 0, &len);
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
len = 0;
status = pNtQueryLicenseValue(&name, NULL, buffer, 0, &len);
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
type = 0xdead;
len = 0;
memset(buffer, 0x11, sizeof(buffer));
status = pNtQueryLicenseValue(&name, &type, buffer, sizeof(buffer), &len);
ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
ok(type == REG_SZ, "expected type = REG_SZ, got %u\n", type);
ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
ok(!memcmp(buffer, emptyW, sizeof(emptyW)), "unexpected buffer content\n");
type = 0xdead;
len = 0;
memset(buffer, 0x11, sizeof(buffer));
status = pNtQueryLicenseValue(&name, &type, buffer, 2, &len);
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
ok(type == REG_SZ, "expected type REG_SZ, got %u\n", type);
ok(len == sizeof(emptyW), "expected len = %u, got %u\n", (DWORD)sizeof(emptyW), len);
ok(buffer[0] == 0x1111, "expected buffer[0] = 0x1111, got %u\n", buffer[0]);
pRtlFreeUnicodeString(&name);
/* test with REG_DWORD license key */
pRtlCreateUnicodeStringFromAsciiz(&name, "Kernel-MUI-Number-Allowed");
type = 0xdead;
len = 0xbeef;
status = pNtQueryLicenseValue(NULL, &type, &value, sizeof(value), &len);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
ok(len == 0xbeef, "expected unmodified value for len, got %u\n", len);
type = 0xdead;
status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), NULL);
ok(status == STATUS_INVALID_PARAMETER, "NtQueryLicenseValue returned %08x, expected STATUS_INVALID_PARAMETER\n", status);
ok(type == 0xdead, "expected unmodified value for type, got %u\n", type);
type = 0xdead;
len = 0;
status = pNtQueryLicenseValue(&name, &type, &value, 0, &len);
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
len = 0;
status = pNtQueryLicenseValue(&name, NULL, &value, 0, &len);
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
type = 0xdead;
len = 0;
value = 0xdeadbeef;
status = pNtQueryLicenseValue(&name, &type, &value, sizeof(value), &len);
ok(status == STATUS_SUCCESS, "NtQueryLicenseValue returned %08x, expected STATUS_SUCCESS\n", status);
ok(type == REG_DWORD, "expected type = REG_DWORD, got %u\n", type);
ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
ok(value != 0xdeadbeef, "expected value != 0xdeadbeef\n");
type = 0xdead;
len = 0;
status = pNtQueryLicenseValue(&name, &type, &value, 2, &len);
ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryLicenseValue returned %08x, expected STATUS_BUFFER_TOO_SMALL\n", status);
ok(type == REG_DWORD, "expected type REG_DWORD, got %u\n", type);
ok(len == sizeof(value), "expected len = %u, got %u\n", (DWORD)sizeof(value), len);
pRtlFreeUnicodeString(&name);
}
static void test_RtlpNtQueryValueKey(void)
{
NTSTATUS status;
@ -1277,6 +1459,51 @@ static void test_long_value_name(void)
pNtClose(key);
}
static void test_NtQueryKey(void)
{
HANDLE key;
NTSTATUS status;
OBJECT_ATTRIBUTES attr;
ULONG length, len;
KEY_NAME_INFORMATION *info = NULL;
UNICODE_STRING str;
InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0);
status = pNtOpenKey(&key, KEY_READ, &attr);
ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status);
status = pNtQueryKey(key, KeyNameInformation, NULL, 0, &length);
if (status == STATUS_INVALID_PARAMETER) {
win_skip("KeyNameInformation is not supported\n");
pNtClose(key);
return;
}
todo_wine ok(status == STATUS_BUFFER_TOO_SMALL, "NtQueryKey Failed: 0x%08x\n", status);
info = HeapAlloc(GetProcessHeap(), 0, length);
/* non-zero buffer size, but insufficient */
status = pNtQueryKey(key, KeyNameInformation, info, sizeof(*info), &len);
ok(status == STATUS_BUFFER_OVERFLOW, "NtQueryKey Failed: 0x%08x\n", status);
ok(length == len, "got %d, expected %d\n", len, length);
ok(info->NameLength == winetestpath.Length, "got %d, expected %d\n",
info->NameLength, winetestpath.Length);
/* correct buffer size */
status = pNtQueryKey(key, KeyNameInformation, info, length, &len);
ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status);
ok(length == len, "got %d, expected %d\n", len, length);
str.Buffer = info->Name;
str.Length = info->NameLength;
ok(pRtlCompareUnicodeString(&winetestpath, &str, TRUE) == 0,
"got %s, expected %s\n",
wine_dbgstr_wn(str.Buffer, str.Length/sizeof(WCHAR)),
wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR)));
HeapFree(GetProcessHeap(), 0, info);
pNtClose(key);
}
START_TEST(reg)
{
static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0};
@ -1297,7 +1524,9 @@ START_TEST(reg)
test_RtlQueryRegistryValues();
test_RtlpNtQueryValueKey();
test_NtFlushKey();
test_NtQueryKey();
test_NtQueryValueKey();
test_NtQueryLicenseKey();
test_long_value_name();
test_NtDeleteKey();
test_symlinks();

View file

@ -62,6 +62,8 @@ static inline USHORT __my_ushort_swap(USHORT s)
/* Function ptrs for ntdll calls */
static HMODULE hntdll = 0;
static PVOID (WINAPI *pWinSqmStartSession)(PVOID unknown1, DWORD unknown2, DWORD unknown3);
static NTSTATUS (WINAPI *pWinSqmEndSession)(PVOID unknown1);
static SIZE_T (WINAPI *pRtlCompareMemory)(LPCVOID,LPCVOID,SIZE_T);
static SIZE_T (WINAPI *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG);
static NTSTATUS (WINAPI *pRtlDeleteTimer)(HANDLE, HANDLE, HANDLE);
@ -89,9 +91,14 @@ static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,US
static CHAR * (WINAPI *pRtlIpv4AddressToStringA)(const IN_ADDR *, LPSTR);
static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG);
static NTSTATUS (WINAPI *pRtlIpv4StringToAddressA)(PCSTR, BOOLEAN, PCSTR *, IN_ADDR *);
static NTSTATUS (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT);
static NTSTATUS (WINAPI *pLdrAddRefDll)(ULONG, HMODULE);
static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG*, ULONG_PTR*);
static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
static NTSTATUS (WINAPI *pRtlGetCompressionWorkSpaceSize)(USHORT, PULONG, PULONG);
static NTSTATUS (WINAPI *pRtlDecompressBuffer)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, PULONG);
static NTSTATUS (WINAPI *pRtlDecompressFragment)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, ULONG, PULONG, PVOID);
static NTSTATUS (WINAPI *pRtlCompressBuffer)(USHORT, const UCHAR*, ULONG, PUCHAR, ULONG, ULONG, PULONG, PVOID);
static HMODULE hkernel32 = 0;
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
@ -109,6 +116,8 @@ static void InitFunctionPtrs(void)
hntdll = LoadLibraryA("ntdll.dll");
ok(hntdll != 0, "LoadLibrary failed\n");
if (hntdll) {
pWinSqmStartSession = (void *)GetProcAddress(hntdll, "WinSqmStartSession");
pWinSqmEndSession = (void *)GetProcAddress(hntdll, "WinSqmEndSession");
pRtlCompareMemory = (void *)GetProcAddress(hntdll, "RtlCompareMemory");
pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong");
pRtlDeleteTimer = (void *)GetProcAddress(hntdll, "RtlDeleteTimer");
@ -136,9 +145,14 @@ static void InitFunctionPtrs(void)
pRtlIpv4AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringA");
pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA");
pRtlIpv4StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressA");
pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA");
pLdrAddRefDll = (void *)GetProcAddress(hntdll, "LdrAddRefDll");
pLdrLockLoaderLock = (void *)GetProcAddress(hntdll, "LdrLockLoaderLock");
pLdrUnlockLoaderLock = (void *)GetProcAddress(hntdll, "LdrUnlockLoaderLock");
pRtlGetCompressionWorkSpaceSize = (void *)GetProcAddress(hntdll, "RtlGetCompressionWorkSpaceSize");
pRtlDecompressBuffer = (void *)GetProcAddress(hntdll, "RtlDecompressBuffer");
pRtlDecompressFragment = (void *)GetProcAddress(hntdll, "RtlDecompressFragment");
pRtlCompressBuffer = (void *)GetProcAddress(hntdll, "RtlCompressBuffer");
}
hkernel32 = LoadLibraryA("kernel32.dll");
ok(hkernel32 != 0, "LoadLibrary failed\n");
@ -149,6 +163,46 @@ static void InitFunctionPtrs(void)
ok(strlen(src) == 15, "Source must be 16 bytes long!\n");
}
#ifdef __i386__
const char stdcall3_thunk[] =
"\x56" /* push %esi */
"\x89\xE6" /* mov %esp, %esi */
"\xFF\x74\x24\x14" /* pushl 20(%esp) */
"\xFF\x74\x24\x14" /* pushl 20(%esp) */
"\xFF\x74\x24\x14" /* pushl 20(%esp) */
"\xFF\x54\x24\x14" /* calll 20(%esp) */
"\x89\xF0" /* mov %esi, %eax */
"\x29\xE0" /* sub %esp, %eax */
"\x89\xF4" /* mov %esi, %esp */
"\x5E" /* pop %esi */
"\xC2\x10\x00" /* ret $16 */
;
static INT (WINAPI *call_stdcall_func3)(PVOID func, PVOID arg0, DWORD arg1, DWORD arg2) = NULL;
static void test_WinSqm(void)
{
INT args;
if (!pWinSqmStartSession)
{
win_skip("WinSqmStartSession() is not available\n");
return;
}
call_stdcall_func3 = (void*) VirtualAlloc( NULL, sizeof(stdcall3_thunk) - 1, MEM_COMMIT,
PAGE_EXECUTE_READWRITE );
memcpy( call_stdcall_func3, stdcall3_thunk, sizeof(stdcall3_thunk) - 1 );
args = 3 - call_stdcall_func3( pWinSqmStartSession, NULL, 0, 0 ) / 4;
ok(args == 3, "WinSqmStartSession expected to take %d arguments instead of 3\n", args);
args = 3 - call_stdcall_func3( pWinSqmEndSession, NULL, 0, 0 ) / 4;
ok(args == 1, "WinSqmEndSession expected to take %d arguments instead of 1\n", args);
VirtualFree( call_stdcall_func3, 0, MEM_RELEASE );
}
#endif
#define COMP(str1,str2,cmplen,len) size = pRtlCompareMemory(str1, str2, cmplen); \
ok(size == len, "Expected %ld, got %ld\n", size, (SIZE_T)len)
@ -1492,6 +1546,94 @@ static void test_RtlIpv4StringToAddress(void)
}
}
static void test_RtlIpv4StringToAddressEx(void)
{
NTSTATUS res;
IN_ADDR ip, expected_ip;
USHORT port;
struct
{
PCSTR address;
NTSTATUS res;
int ip[4];
USHORT port;
} tests[] =
{
{ "", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
{ " ", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
{ "1.1.1.1:", STATUS_INVALID_PARAMETER, { 1, 1, 1, 1 }, 0xdead },
{ "1.1.1.1+", STATUS_INVALID_PARAMETER, { 1, 1, 1, 1 }, 0xdead },
{ "1.1.1.1:1", STATUS_SUCCESS, { 1, 1, 1, 1 }, 0x100 },
{ "0.0.0.0:0", STATUS_INVALID_PARAMETER, { 0, 0, 0, 0 }, 0xdead },
{ "0.0.0.0:1", STATUS_SUCCESS, { 0, 0, 0, 0 }, 0x100 },
{ "1.2.3.4:65535", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
{ "1.2.3.4:65536", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
{ "1.2.3.4:0xffff", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
{ "1.2.3.4:0XfFfF", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
{ "1.2.3.4:011064", STATUS_SUCCESS, { 1, 2, 3, 4 }, 0x3412 },
{ "1.2.3.4:1234a", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
{ "1.2.3.4:1234+", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
{ "1.2.3.4: 1234", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
{ "1.2.3.4:\t1234", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
};
const int testcount = sizeof(tests) / sizeof(tests[0]);
int i, Strict;
if (!pRtlIpv4StringToAddressExA)
{
skip("RtlIpv4StringToAddressEx not available\n");
return;
}
/* do not crash, and do not touch the ip / port. */
ip.S_un.S_addr = 0xabababab;
port = 0xdead;
res = pRtlIpv4StringToAddressExA(NULL, FALSE, &ip, &port);
ok(res == STATUS_INVALID_PARAMETER, "[null address] res = 0x%08x, expected 0x%08x\n", res, STATUS_INVALID_PARAMETER);
ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
port = 0xdead;
res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, NULL, &port);
ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected 0x%08x\n", res, STATUS_INVALID_PARAMETER);
ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
ip.S_un.S_addr = 0xabababab;
port = 0xdead;
res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, &ip, NULL);
ok(res == STATUS_INVALID_PARAMETER, "[null port] res = 0x%08x, expected 0x%08x\n", res, STATUS_INVALID_PARAMETER);
ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
for (i = 0; i < testcount; i++)
{
/* Strict is only relevant for the ip address, so make sure that it does not influence the port */
for (Strict = 0; Strict < 2; Strict++)
{
ip.S_un.S_addr = 0xabababab;
port = 0xdead;
res = pRtlIpv4StringToAddressExA(tests[i].address, Strict, &ip, &port);
if (tests[i].ip[0] == -1)
{
expected_ip.S_un.S_addr = 0xabababab;
}
else
{
expected_ip.S_un.S_un_b.s_b1 = tests[i].ip[0];
expected_ip.S_un.S_un_b.s_b2 = tests[i].ip[1];
expected_ip.S_un.S_un_b.s_b3 = tests[i].ip[2];
expected_ip.S_un.S_un_b.s_b4 = tests[i].ip[3];
}
ok(res == tests[i].res, "[%s] res = 0x%08x, expected 0x%08x\n",
tests[i].address, res, tests[i].res);
ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
ok(port == tests[i].port, "[%s] port = %u, expected %u\n",
tests[i].address, port, tests[i].port);
}
}
}
static void test_LdrAddRefDll(void)
{
HMODULE mod, mod2;
@ -1599,10 +1741,745 @@ static void test_LdrLockLoaderLock(void)
pLdrUnlockLoaderLock(0, magic);
}
static void test_RtlGetCompressionWorkSpaceSize(void)
{
ULONG compress_workspace, decompress_workspace;
NTSTATUS status;
if (!pRtlGetCompressionWorkSpaceSize)
{
win_skip("RtlGetCompressionWorkSpaceSize is not available\n");
return;
}
status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_NONE, &compress_workspace,
&decompress_workspace);
ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_DEFAULT, &compress_workspace,
&decompress_workspace);
ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
status = pRtlGetCompressionWorkSpaceSize(0xFF, &compress_workspace, &decompress_workspace);
ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
compress_workspace = decompress_workspace = 0xdeadbeef;
status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, &compress_workspace,
&decompress_workspace);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
ok(compress_workspace != 0, "got wrong compress_workspace %d\n", compress_workspace);
ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %d\n", decompress_workspace);
compress_workspace = decompress_workspace = 0xdeadbeef;
status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM,
&compress_workspace, &decompress_workspace);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
ok(compress_workspace != 0, "got wrong compress_workspace %d\n", compress_workspace);
ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %d\n", decompress_workspace);
}
/* helper for test_RtlDecompressBuffer, checks if a chunk is incomplete */
static BOOL is_incomplete_chunk(const UCHAR *compressed, ULONG compressed_size, BOOL check_all)
{
ULONG chunk_size;
if (compressed_size <= sizeof(WORD))
return TRUE;
while (compressed_size >= sizeof(WORD))
{
chunk_size = (*(WORD *)compressed & 0xFFF) + 1;
if (compressed_size < sizeof(WORD) + chunk_size)
return TRUE;
if (!check_all)
break;
compressed += sizeof(WORD) + chunk_size;
compressed_size -= sizeof(WORD) + chunk_size;
}
return FALSE;
}
#define DECOMPRESS_BROKEN_TRUNCATED 1
#define DECOMPRESS_BROKEN_FRAGMENT0 2
#define DECOMPRESS_BROKEN_FRAGMENT1 4
#define DECOMPRESS_BROKEN_FRAGMENT4095 8
static void test_RtlDecompressBuffer(void)
{
static const UCHAR test_multiple_chunks[] = {0x03, 0x30, 'W', 'i', 'n', 'e',
0x03, 0x30, 'W', 'i', 'n', 'e'};
static const struct
{
UCHAR compressed[32];
ULONG compressed_size;
NTSTATUS status;
UCHAR uncompressed[32];
ULONG uncompressed_size;
DWORD broken_flags;
}
test_lznt[] =
{
/* 4 byte uncompressed chunk */
{
{0x03, 0x30, 'W', 'i', 'n', 'e'},
6,
STATUS_SUCCESS,
"Wine",
4,
DECOMPRESS_BROKEN_FRAGMENT4095 |
DECOMPRESS_BROKEN_FRAGMENT1 |
DECOMPRESS_BROKEN_FRAGMENT0
},
/* 8 byte uncompressed chunk */
{
{0x07, 0x30, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
10,
STATUS_SUCCESS,
"WineWine",
8,
DECOMPRESS_BROKEN_FRAGMENT4095 |
DECOMPRESS_BROKEN_FRAGMENT1 |
DECOMPRESS_BROKEN_FRAGMENT0
},
/* 4 byte compressed chunk */
{
{0x04, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
7,
STATUS_SUCCESS,
"Wine",
4
},
/* 8 byte compressed chunk */
{
{0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
11,
STATUS_SUCCESS,
"WineWine",
8
},
/* compressed chunk using backwards reference */
{
{0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x01, 0x30},
9,
STATUS_SUCCESS,
"WineWine",
8,
DECOMPRESS_BROKEN_TRUNCATED
},
/* compressed chunk using backwards reference with length > bytes_read */
{
{0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x30},
9,
STATUS_SUCCESS,
"WineWineWine",
12,
DECOMPRESS_BROKEN_TRUNCATED
},
/* same as above, but unused bits != 0 */
{
{0x06, 0xB0, 0x30, 'W', 'i', 'n', 'e', 0x01, 0x30},
9,
STATUS_SUCCESS,
"WineWine",
8,
DECOMPRESS_BROKEN_TRUNCATED
},
/* compressed chunk without backwards reference and unused bits != 0 */
{
{0x01, 0xB0, 0x02, 'W'},
4,
STATUS_SUCCESS,
"W",
1
},
/* termination sequence after first chunk */
{
{0x03, 0x30, 'W', 'i', 'n', 'e', 0x00, 0x00, 0x03, 0x30, 'W', 'i', 'n', 'e'},
14,
STATUS_SUCCESS,
"Wine",
4,
DECOMPRESS_BROKEN_FRAGMENT4095 |
DECOMPRESS_BROKEN_FRAGMENT1 |
DECOMPRESS_BROKEN_FRAGMENT0
},
/* compressed chunk using backwards reference with 4 bit offset, 12 bit length */
{
{0x14, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
0x01, 0x01, 0xF0},
23,
STATUS_SUCCESS,
"ABCDEFGHIJKLMNOPABCD",
20,
DECOMPRESS_BROKEN_TRUNCATED
},
/* compressed chunk using backwards reference with 5 bit offset, 11 bit length */
{
{0x15, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
0x02, 'A', 0x00, 0x78},
24,
STATUS_SUCCESS,
"ABCDEFGHIJKLMNOPABCD",
20,
DECOMPRESS_BROKEN_TRUNCATED
},
/* uncompressed chunk with invalid magic */
{
{0x03, 0x20, 'W', 'i', 'n', 'e'},
6,
STATUS_SUCCESS,
"Wine",
4,
DECOMPRESS_BROKEN_FRAGMENT4095 |
DECOMPRESS_BROKEN_FRAGMENT1 |
DECOMPRESS_BROKEN_FRAGMENT0
},
/* compressed chunk with invalid magic */
{
{0x04, 0xA0, 0x00, 'W', 'i', 'n', 'e'},
7,
STATUS_SUCCESS,
"Wine",
4
},
/* garbage byte after end of buffer */
{
{0x00, 0xB0, 0x02, 0x01},
4,
STATUS_SUCCESS,
"",
0
},
/* empty compressed chunk */
{
{0x00, 0xB0, 0x00},
3,
STATUS_SUCCESS,
"",
0
},
/* empty compressed chunk with unused bits != 0 */
{
{0x00, 0xB0, 0x01},
3,
STATUS_SUCCESS,
"",
0
},
/* empty input buffer */
{
{0},
0,
STATUS_BAD_COMPRESSION_BUFFER,
},
/* incomplete chunk header */
{
{0x01},
1,
STATUS_BAD_COMPRESSION_BUFFER
},
/* incomplete chunk header */
{
{0x00, 0x30},
2,
STATUS_BAD_COMPRESSION_BUFFER
},
/* compressed chunk with invalid backwards reference */
{
{0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x40},
9,
STATUS_BAD_COMPRESSION_BUFFER
},
/* compressed chunk with incomplete backwards reference */
{
{0x05, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05},
8,
STATUS_BAD_COMPRESSION_BUFFER
},
/* incomplete uncompressed chunk */
{
{0x07, 0x30, 'W', 'i', 'n', 'e'},
6,
STATUS_BAD_COMPRESSION_BUFFER
},
/* incomplete compressed chunk */
{
{0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
7,
STATUS_BAD_COMPRESSION_BUFFER
},
/* two compressed chunks, the second one incomplete */
{
{0x00, 0xB0, 0x02, 0x00, 0xB0},
5,
STATUS_BAD_COMPRESSION_BUFFER,
}
};
static UCHAR buf[0x2000], workspace[0x1000];
NTSTATUS status, expected_status;
ULONG final_size;
int i;
if (!pRtlDecompressBuffer || !pRtlDecompressFragment)
{
win_skip("RtlDecompressBuffer or RtlDecompressFragment is not available\n");
return;
}
/* test compression format / engine */
final_size = 0xdeadbeef;
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_NONE, buf, sizeof(buf) - 1, test_lznt[0].compressed,
test_lznt[0].compressed_size, &final_size);
ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
final_size = 0xdeadbeef;
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_DEFAULT, buf, sizeof(buf) - 1, test_lznt[0].compressed,
test_lznt[0].compressed_size, &final_size);
ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
final_size = 0xdeadbeef;
status = pRtlDecompressBuffer(0xFF, buf, sizeof(buf) - 1, test_lznt[0].compressed,
test_lznt[0].compressed_size, &final_size);
ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
/* regular tests for RtlDecompressBuffer */
for (i = 0; i < sizeof(test_lznt) / sizeof(test_lznt[0]); i++)
{
trace("Running test %d (compressed_size=%d, compressed_size=%d, status=%d)\n",
i, test_lznt[i].compressed_size, test_lznt[i].compressed_size, test_lznt[i].status);
/* test with very big buffer */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
test_lznt[i].compressed_size, &final_size);
ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
ok(final_size == test_lznt[i].uncompressed_size,
"%d: got wrong final_size %d\n", i, final_size);
ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
"%d: got wrong decoded data\n", i);
ok(buf[test_lznt[i].uncompressed_size] == 0x11,
"%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
}
/* test that modifier for compression engine is ignored */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, buf, sizeof(buf),
test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
ok(final_size == test_lznt[i].uncompressed_size,
"%d: got wrong final_size %d\n", i, final_size);
ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
"%d: got wrong decoded data\n", i);
ok(buf[test_lznt[i].uncompressed_size] == 0x11,
"%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
}
/* test with expected output size */
if (test_lznt[i].uncompressed_size > 0)
{
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size,
test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
ok(final_size == test_lznt[i].uncompressed_size,
"%d: got wrong final_size %d\n", i, final_size);
ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
"%d: got wrong decoded data\n", i);
ok(buf[test_lznt[i].uncompressed_size] == 0x11,
"%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
}
}
/* test with smaller output size */
if (test_lznt[i].uncompressed_size > 1)
{
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size - 1,
test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
(test_lznt[i].broken_flags & DECOMPRESS_BROKEN_TRUNCATED)), "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
ok(final_size == test_lznt[i].uncompressed_size - 1,
"%d: got wrong final_size %d\n", i, final_size);
ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size - 1),
"%d: got wrong decoded data\n", i);
ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
"%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size - 1);
}
}
/* test with zero output size */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 0, test_lznt[i].compressed,
test_lznt[i].compressed_size, &final_size);
if (is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, FALSE))
{
ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
}
else
{
ok(status == STATUS_SUCCESS, "%d: got wrong status 0x%08x\n", i, status);
ok(final_size == 0, "%d: got wrong final_size %d\n", i, final_size);
ok(buf[0] == 0x11, "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
}
/* test RtlDecompressBuffer with offset = 0 */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
test_lznt[i].compressed_size, 0, &final_size, workspace);
ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
(test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT0)), "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
ok(final_size == test_lznt[i].uncompressed_size,
"%d: got wrong final_size %d\n", i, final_size);
ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
"%d: got wrong decoded data\n", i);
ok(buf[test_lznt[i].uncompressed_size] == 0x11,
"%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
}
/* test RtlDecompressBuffer with offset = 1 */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
test_lznt[i].compressed_size, 1, &final_size, workspace);
ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
(test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT1)), "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
if (test_lznt[i].uncompressed_size == 0)
{
todo_wine
ok(final_size == 4095,
"%d: got wrong final size %d\n", i, final_size);
/* Buffer doesn't contain any useful value on Windows */
ok(buf[4095] == 0x11,
"%d: buf[4095] overwritten\n", i);
}
else
{
ok(final_size == test_lznt[i].uncompressed_size - 1,
"%d: got wrong final_size %d\n", i, final_size);
ok(!memcmp(buf, test_lznt[i].uncompressed + 1, test_lznt[i].uncompressed_size - 1),
"%d: got wrong decoded data\n", i);
ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
"%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size - 1);
}
}
/* test RtlDecompressBuffer with offset = 4095 */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
test_lznt[i].compressed_size, 4095, &final_size, workspace);
ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
(test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT4095)), "%d: got wrong status 0x%08x\n", i, status);
if (!status)
{
todo_wine
ok(final_size == 1,
"%d: got wrong final size %d\n", i, final_size);
todo_wine
ok(buf[0] == 0,
"%d: padding is not zero\n", i);
ok(buf[1] == 0x11,
"%d: buf[1] overwritten\n", i);
}
/* test RtlDecompressBuffer with offset = 4096 */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
test_lznt[i].compressed_size, 4096, &final_size, workspace);
expected_status = is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, TRUE) ?
test_lznt[i].status : STATUS_SUCCESS;
ok(status == expected_status, "%d: got wrong status 0x%08x, expected 0x%08x\n", i, status, expected_status);
if (!status)
{
ok(final_size == 0,
"%d: got wrong final size %d\n", i, final_size);
ok(buf[0] == 0x11,
"%d: buf[4096] overwritten\n", i);
}
}
/* test decoding of multiple chunks with pRtlDecompressBuffer */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
sizeof(test_multiple_chunks), &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4100, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
ok(buf[4] == 0 && buf[4095] == 0, "padding is not zero\n");
ok(!memcmp(buf + 4096, "Wine", 4), "got wrong decoded data at offset 4096\n");
ok(buf[4100] == 0x11, "buf[4100] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 4097, test_multiple_chunks,
sizeof(test_multiple_chunks), &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4097, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
ok(buf[4] == 0 && buf[4095] == 0, "padding is not zero\n");
ok(buf[4096], "got wrong decoded data at offset 4096\n");
ok(buf[4097] == 0x11, "buf[4097] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 4096, test_multiple_chunks,
sizeof(test_multiple_chunks), &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
ok(buf[4] == 0x11, "buf[4] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 4, test_multiple_chunks,
sizeof(test_multiple_chunks), &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
ok(buf[4] == 0x11, "buf[4] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 3, test_multiple_chunks,
sizeof(test_multiple_chunks), &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 3, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "Wine", 3), "got wrong decoded data at offset 0\n");
ok(buf[3] == 0x11, "buf[3] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 0, test_multiple_chunks,
sizeof(test_multiple_chunks), &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 0, "got wrong final_size %d\n", final_size);
ok(buf[0] == 0x11, "buf[0] overwritten\n");
}
/* test multiple chunks in combination with RtlDecompressBuffer and offset=1 */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
sizeof(test_multiple_chunks), 1, &final_size, workspace);
ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
"got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4099, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
ok(buf[3] == 0 && buf[4094] == 0, "padding is not zero\n");
ok(!memcmp(buf + 4095, "Wine", 4), "got wrong decoded data at offset 4095\n");
ok(buf[4099] == 0x11, "buf[4099] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, 4096, test_multiple_chunks,
sizeof(test_multiple_chunks), 1, &final_size, workspace);
ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
"got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4096, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
ok(buf[3] == 0 && buf[4094] == 0, "padding is not zero\n");
ok(buf[4095] == 'W', "got wrong decoded data at offset 4095\n");
ok(buf[4096] == 0x11, "buf[4096] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, 4095, test_multiple_chunks,
sizeof(test_multiple_chunks), 1, &final_size, workspace);
ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
"got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 3, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
ok(buf[4] == 0x11, "buf[4] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, 3, test_multiple_chunks,
sizeof(test_multiple_chunks), 1, &final_size, workspace);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 3, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
ok(buf[3] == 0x11, "buf[3] overwritten\n");
}
/* test multiple chunks in combination with RtlDecompressBuffer and offset=4 */
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
sizeof(test_multiple_chunks), 4, &final_size, workspace);
ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
"got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4096, "got wrong final_size %d\n", final_size);
ok(buf[0] == 0 && buf[4091] == 0, "padding is not zero\n");
ok(!memcmp(buf + 4092, "Wine", 4), "got wrong decoded data at offset 4092\n");
ok(buf[4096] == 0x11, "buf[4096] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
sizeof(test_multiple_chunks), 4095, &final_size, workspace);
ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
"got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 5, "got wrong final_size %d\n", final_size);
ok(buf[0] == 0, "padding is not zero\n");
ok(!memcmp(buf + 1, "Wine", 4), "got wrong decoded data at offset 1\n");
ok(buf[5] == 0x11, "buf[5] overwritten\n");
}
final_size = 0xdeadbeef;
memset(buf, 0x11, sizeof(buf));
status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
sizeof(test_multiple_chunks), 4096, &final_size, workspace);
ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
"got wrong status 0x%08x\n", status);
if (!status)
{
ok(final_size == 4, "got wrong final_size %d\n", final_size);
ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
ok(buf[4] == 0x11, "buf[4] overwritten\n");
}
}
static void test_RtlCompressBuffer(void)
{
ULONG compress_workspace, decompress_workspace;
static const UCHAR test_buffer[] = "WineWineWine";
static UCHAR buf1[0x1000], buf2[0x1000], *workspace;
ULONG final_size, buf_size;
NTSTATUS status;
if (!pRtlCompressBuffer || !pRtlGetCompressionWorkSpaceSize)
{
win_skip("RtlCompressBuffer or RtlGetCompressionWorkSpaceSize is not available\n");
return;
}
compress_workspace = decompress_workspace = 0xdeadbeef;
status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, &compress_workspace,
&decompress_workspace);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
ok(compress_workspace != 0, "got wrong compress_workspace %d\n", compress_workspace);
workspace = HeapAlloc( GetProcessHeap(), 0, compress_workspace );
ok(workspace != NULL, "HeapAlloc failed %x\n", GetLastError());
/* test compression format / engine */
final_size = 0xdeadbeef;
status = pRtlCompressBuffer(COMPRESSION_FORMAT_NONE, test_buffer, sizeof(test_buffer),
buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
final_size = 0xdeadbeef;
status = pRtlCompressBuffer(COMPRESSION_FORMAT_DEFAULT, test_buffer, sizeof(test_buffer),
buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
final_size = 0xdeadbeef;
status = pRtlCompressBuffer(0xFF, test_buffer, sizeof(test_buffer),
buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
/* test compression */
final_size = 0xdeadbeef;
memset(buf1, 0x11, sizeof(buf1));
status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer),
buf1, sizeof(buf1), 4096, &final_size, workspace);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
ok((*(WORD *)buf1 & 0x7000) == 0x3000, "no chunk signature found %04x\n", *(WORD *)buf1);
buf_size = final_size;
todo_wine
ok(final_size < sizeof(test_buffer), "got wrong final_size %d\n", final_size);
/* test decompression */
final_size = 0xdeadbeef;
memset(buf2, 0x11, sizeof(buf2));
status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf2, sizeof(buf2),
buf1, buf_size, &final_size);
ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
ok(final_size == sizeof(test_buffer), "got wrong final_size %d\n", final_size);
ok(!memcmp(buf2, test_buffer, sizeof(test_buffer)), "got wrong decoded data\n");
ok(buf2[sizeof(test_buffer)] == 0x11, "buf[%u] overwritten\n", (DWORD)sizeof(test_buffer));
/* buffer too small */
final_size = 0xdeadbeef;
memset(buf1, 0x11, sizeof(buf1));
status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer),
buf1, 4, 4096, &final_size, workspace);
ok(status == STATUS_BUFFER_TOO_SMALL, "got wrong status 0x%08x\n", status);
HeapFree(GetProcessHeap(), 0, workspace);
}
START_TEST(rtl)
{
InitFunctionPtrs();
#ifdef __i386__
test_WinSqm();
#else
skip("stdcall-style parameter checks are not supported on this platform.\n");
#endif
test_RtlCompareMemory();
test_RtlCompareMemoryUlong();
test_RtlMoveMemory();
@ -1623,6 +2500,10 @@ START_TEST(rtl)
test_RtlIpv4AddressToString();
test_RtlIpv4AddressToStringEx();
test_RtlIpv4StringToAddress();
test_RtlIpv4StringToAddressEx();
test_LdrAddRefDll();
test_LdrLockLoaderLock();
test_RtlGetCompressionWorkSpaceSize();
test_RtlDecompressBuffer();
test_RtlCompressBuffer();
}

View file

@ -1083,8 +1083,8 @@ static void test_atoi64(void)
result = p_atoi64(str2longlong[test_num].str);
if (str2longlong[test_num].overflow)
ok(result == str2longlong[test_num].value ||
(result == (str2longlong[test_num].overflow == -1) ?
ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff)),
(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);
@ -1108,8 +1108,8 @@ static void test_wtoi64(void)
result = p_wtoi64(uni.Buffer);
if (str2longlong[test_num].overflow)
ok(result == str2longlong[test_num].value ||
(result == (str2longlong[test_num].overflow == -1) ?
ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff)),
(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);