mirror of
https://github.com/reactos/reactos.git
synced 2025-07-24 18:03:44 +00:00
[NTDLL_WINETEST] Sync with Wine Staging 1.7.37. CORE-9246
svn path=/trunk/; revision=66658
This commit is contained in:
parent
6bd29991d4
commit
26326ca7d5
8 changed files with 1560 additions and 47 deletions
|
@ -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++;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue