From 20ba26ecba0fd209a25894b2d9f63cfdf660fd59 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Tue, 24 Nov 2015 15:14:42 +0000 Subject: [PATCH] [NTDLL_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536 svn path=/trunk/; revision=70096 --- rostests/winetests/ntdll/CMakeLists.txt | 2 +- rostests/winetests/ntdll/directory.c | 98 +- rostests/winetests/ntdll/env.c | 2 +- rostests/winetests/ntdll/exception.c | 4 +- rostests/winetests/ntdll/file.c | 1620 ++++++++++++++++++++++- rostests/winetests/ntdll/generated.c | 402 ++++-- rostests/winetests/ntdll/info.c | 106 +- rostests/winetests/ntdll/om.c | 84 +- rostests/winetests/ntdll/reg.c | 204 ++- rostests/winetests/ntdll/rtl.c | 744 ++++------- 10 files changed, 2578 insertions(+), 688 deletions(-) diff --git a/rostests/winetests/ntdll/CMakeLists.txt b/rostests/winetests/ntdll/CMakeLists.txt index 815f3d0010c..7a843e1c276 100644 --- a/rostests/winetests/ntdll/CMakeLists.txt +++ b/rostests/winetests/ntdll/CMakeLists.txt @@ -34,5 +34,5 @@ add_importlibs(ntdll_winetest user32 msvcrt kernel32 ntdll) add_cd_file(TARGET ntdll_winetest DESTINATION reactos/bin FOR all) if(NOT MSVC) - add_target_compile_flags(ntdll_winetest "-Wno-format") + add_target_compile_flags(ntdll_winetest "-Wno-format -Wno-error") endif() diff --git a/rostests/winetests/ntdll/directory.c b/rostests/winetests/ntdll/directory.c index b541f0cfe92..89b786d384a 100644 --- a/rostests/winetests/ntdll/directory.c +++ b/rostests/winetests/ntdll/directory.c @@ -174,7 +174,7 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char data_size = mask ? offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ) : sizeof(data); /* Read the directory and note which files are found */ - status = pNtOpenFile( &dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, attr, &io, FILE_OPEN, + status = pNtOpenFile( &dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_DIRECTORY_FILE); ok (status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%x, error %d\n", testdirA, status, GetLastError()); if (status != STATUS_SUCCESS) { @@ -270,6 +270,101 @@ done: pRtlFreeUnicodeString(&ntdirname); } +static void set_up_case_test(const char *testdir) +{ + BOOL ret; + char buf[MAX_PATH]; + HANDLE h; + + ret = CreateDirectoryA(testdir, NULL); + ok(ret, "couldn't create dir '%s', error %d\n", testdir, GetLastError()); + + sprintf(buf, "%s\\%s", testdir, "TesT"); + h = CreateFileA(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + ok(h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf); + CloseHandle(h); +} + +static void tear_down_case_test(const char *testdir) +{ + int ret; + char buf[MAX_PATH]; + + sprintf(buf, "%s\\%s", testdir, "TesT"); + ret = DeleteFileA(buf); + ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), + "Failed to rm %s, error %d\n", buf, GetLastError()); + RemoveDirectoryA(testdir); +} + +static void test_NtQueryDirectoryFile_case(void) +{ + static const char testfile[] = "TesT"; + static const WCHAR testfile_w[] = {'T','e','s','T'}; + static int testfile_len = sizeof(testfile) - 1; + static WCHAR testmask[] = {'t','e','s','t'}; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING ntdirname; + char testdir[MAX_PATH]; + WCHAR testdir_w[MAX_PATH]; + HANDLE dirh; + UNICODE_STRING mask; + IO_STATUS_BLOCK io; + UINT data_size, data_len; + BYTE data[8192]; + FILE_BOTH_DIRECTORY_INFORMATION *dir_info = (FILE_BOTH_DIRECTORY_INFORMATION *)data; + DWORD status; + WCHAR *name; + ULONG name_len; + + /* Clean up from prior aborted run, if any, then set up test files */ + ok(GetTempPathA(MAX_PATH, testdir), "couldn't get temp dir\n"); + strcat(testdir, "case.tmp"); + tear_down_case_test(testdir); + set_up_case_test(testdir); + + pRtlMultiByteToUnicodeN(testdir_w, sizeof(testdir_w), NULL, testdir, strlen(testdir) + 1); + if (!pRtlDosPathNameToNtPathName_U(testdir_w, &ntdirname, NULL, NULL)) + { + ok(0, "RtlDosPathNametoNtPathName_U failed\n"); + goto done; + } + InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); + + data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]); + + status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); + ok (status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%x, error %d\n", testdir, status, GetLastError()); + if (status != STATUS_SUCCESS) + { + skip("can't test if we can't open the directory\n"); + return; + } + + mask.Buffer = testmask; + mask.Length = mask.MaximumLength = sizeof(testmask); + pNtQueryDirectoryFile(dirh, NULL, NULL, NULL, &io, data, data_size, + FileBothDirectoryInformation, TRUE, &mask, FALSE); + ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status); + data_len = io.Information; + ok(data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n"); + + name = dir_info->FileName; + name_len = dir_info->FileNameLength / sizeof(WCHAR); + + ok(name_len == testfile_len, "unexpected filename length %u\n", name_len); + ok(!memcmp(name, testfile_w, testfile_len * sizeof(WCHAR)), "unexpected filename %s\n", + wine_dbgstr_wn(name, name_len)); + + pNtClose(dirh); + +done: + tear_down_case_test(testdir); + pRtlFreeUnicodeString(&ntdirname); +} + static void test_redirection(void) { ULONG old, cur; @@ -339,5 +434,6 @@ START_TEST(directory) pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirectionEx"); test_NtQueryDirectoryFile(); + test_NtQueryDirectoryFile_case(); test_redirection(); } diff --git a/rostests/winetests/ntdll/env.c b/rostests/winetests/ntdll/env.c index 6bd15305e91..8989760f43c 100755 --- a/rostests/winetests/ntdll/env.c +++ b/rostests/winetests/ntdll/env.c @@ -111,7 +111,7 @@ static void testQuery(void) pRtlMultiByteToUnicodeN( bn, sizeof(bn), NULL, test->val, strlen(test->val)+1 ); ok( value.Length == strlen(test->val) * sizeof(WCHAR), "Wrong length %d for %s\n", value.Length, test->var ); - ok((value.Length == strlen(test->val) * sizeof(WCHAR) && memcmp(bv, bn, test->len*sizeof(WCHAR)) == 0) || + ok((value.Length == strlen(test->val) * sizeof(WCHAR) && memcmp(bv, bn, value.Length) == 0) || lstrcmpW(bv, bn) == 0, "Wrong result for %s/%d\n", test->var, test->len); ok(bv[test->len] == '@', "Writing too far away in the buffer for %s/%d\n", test->var, test->len); diff --git a/rostests/winetests/ntdll/exception.c b/rostests/winetests/ntdll/exception.c index 8e7894ee345..2455e1b6f15 100644 --- a/rostests/winetests/ntdll/exception.c +++ b/rostests/winetests/ntdll/exception.c @@ -973,7 +973,7 @@ static void test_debugger(void) sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%x\n", status); - ok(!de.u.DebugString.fUnicode, "unepxected unicode debug string event\n"); + ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength); @@ -1838,7 +1838,7 @@ static void test_closehandle(DWORD numexc) 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", + ok(GetLastError() == ERROR_INVALID_HANDLE, "wrong error code %d instead of %d\n", GetLastError(), ERROR_INVALID_HANDLE); ok(invalid_handle_exceptions == numexc, "CloseHandle generated %d exceptions, expected %d\n", invalid_handle_exceptions, numexc); diff --git a/rostests/winetests/ntdll/file.c b/rostests/winetests/ntdll/file.c index 0acc7cf574d..706984abce8 100644 --- a/rostests/winetests/ntdll/file.c +++ b/rostests/winetests/ntdll/file.c @@ -105,6 +105,8 @@ static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOI static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK, PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN); static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS); +static NTSTATUS (WINAPI *pNtQueryFullAttributesFile)(const OBJECT_ATTRIBUTES*, FILE_NETWORK_OPEN_INFORMATION*); +static NTSTATUS (WINAPI *pNtQueryEaFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,BOOLEAN,PVOID,ULONG,PULONG,BOOLEAN); static inline BOOL is_signaled( HANDLE obj ) { @@ -200,12 +202,20 @@ static void create_file_test(void) '\\','f','a','i','l','i','n','g',0}; static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0}; static const WCHAR pipeInvalidNameW[] = {'a','|','b',0}; + static const WCHAR pathInvalidNtW[] = {'\\','\\','?','\\',0}; + static const WCHAR pathInvalidNt2W[] = {'\\','?','?','\\',0}; + static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0}; + static const char testdata[] = "Hello World"; + FILE_NETWORK_OPEN_INFORMATION info; NTSTATUS status; HANDLE dir, file; WCHAR path[MAX_PATH]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; UNICODE_STRING nameW; + LARGE_INTEGER offset; + char buf[32]; + DWORD ret; GetCurrentDirectoryW( MAX_PATH, path ); pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); @@ -217,9 +227,35 @@ static void create_file_test(void) attr.SecurityQualityOfService = NULL; /* try various open modes and options on directories */ - status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 ); + status = pNtCreateFile( &dir, GENERIC_READ|GENERIC_WRITE, &attr, &io, NULL, 0, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 ); ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + U(io).Status = 0xdeadbeef; + offset.QuadPart = 0; + status = pNtReadFile( dir, NULL, NULL, NULL, &io, buf, sizeof(buf), &offset, NULL ); + ok( status == STATUS_INVALID_DEVICE_REQUEST || status == STATUS_PENDING, "NtReadFile error %08x\n", status ); + if (status == STATUS_PENDING) + { + ret = WaitForSingleObject( dir, 1000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", ret ); + ok( U(io).Status == STATUS_INVALID_DEVICE_REQUEST, + "expected STATUS_INVALID_DEVICE_REQUEST, got %08x\n", U(io).Status ); + } + + U(io).Status = 0xdeadbeef; + offset.QuadPart = 0; + status = pNtWriteFile( dir, NULL, NULL, NULL, &io, testdata, sizeof(testdata), &offset, NULL); + todo_wine + ok( status == STATUS_INVALID_DEVICE_REQUEST || status == STATUS_PENDING, "NtWriteFile error %08x\n", status ); + if (status == STATUS_PENDING) + { + ret = WaitForSingleObject( dir, 1000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", ret ); + ok( U(io).Status == STATUS_INVALID_DEVICE_REQUEST, + "expected STATUS_INVALID_DEVICE_REQUEST, got %08x\n", U(io).Status ); + } + CloseHandle( dir ); status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, @@ -320,19 +356,55 @@ static void create_file_test(void) ok(status == STATUS_OBJECT_NAME_INVALID, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status); pRtlFreeUnicodeString(&nameW); + + pRtlInitUnicodeString( &nameW, pathInvalidNtW ); + status = pNtCreateFile( &dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0, + FILE_SHARE_READ, FILE_CREATE, + FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtQueryFullAttributesFile( &attr, &info ); + todo_wine ok( status == STATUS_OBJECT_NAME_INVALID, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + pRtlInitUnicodeString( &nameW, pathInvalidNt2W ); + status = pNtCreateFile( &dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0, + FILE_SHARE_READ, FILE_CREATE, + FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtQueryFullAttributesFile( &attr, &info ); + ok( status == STATUS_OBJECT_NAME_INVALID, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + pRtlInitUnicodeString( &nameW, pathInvalidDosW ); + status = pNtCreateFile( &dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0, + FILE_SHARE_READ, FILE_CREATE, + FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + ok( status == STATUS_OBJECT_NAME_INVALID, + "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + status = pNtQueryFullAttributesFile( &attr, &info ); + ok( status == STATUS_OBJECT_NAME_INVALID, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); } static void open_file_test(void) { + static const char testdata[] = "Hello World"; + static WCHAR fooW[] = {'f','o','o',0}; NTSTATUS status; - HANDLE dir, root, handle; - WCHAR path[MAX_PATH]; + HANDLE dir, root, handle, file; + WCHAR path[MAX_PATH], tmpfile[MAX_PATH]; BYTE data[1024]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; UNICODE_STRING nameW; UINT i, len; - BOOL restart = TRUE; + BOOL ret, restart = TRUE; + DWORD numbytes; len = GetWindowsDirectoryW( path, MAX_PATH ); pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); @@ -453,6 +525,74 @@ static void open_file_test(void) CloseHandle( dir ); CloseHandle( root ); + + GetTempPathW( MAX_PATH, path ); + GetTempFileNameW( path, fooW, 0, tmpfile ); + pRtlDosPathNameToNtPathName_U( tmpfile, &nameW, NULL, NULL ); + + file = CreateFileW( tmpfile, FILE_WRITE_DATA, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError() ); + numbytes = 0xdeadbeef; + ret = WriteFile( file, testdata, sizeof(testdata) - 1, &numbytes, NULL ); + ok( ret, "WriteFile failed with error %u\n", GetLastError() ); + ok( numbytes == sizeof(testdata) - 1, "failed to write all data\n" ); + CloseHandle( file ); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + status = pNtOpenFile( &file, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + pRtlFreeUnicodeString( &nameW ); + + numbytes = 0xdeadbeef; + memset( data, 0, sizeof(data) ); + ret = ReadFile( file, data, sizeof(data), &numbytes, NULL ); + ok( ret, "ReadFile failed with error %u\n", GetLastError() ); + ok( numbytes == sizeof(testdata) - 1, "failed to read all data\n" ); + ok( !memcmp( data, testdata, sizeof(testdata) - 1 ), "testdata doesn't match\n" ); + + nameW.Length = sizeof(fooW) - sizeof(WCHAR); + nameW.Buffer = fooW; + attr.RootDirectory = file; + attr.ObjectName = &nameW; + status = pNtOpenFile( &root, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); + ok( status == STATUS_OBJECT_PATH_NOT_FOUND, + "expected STATUS_OBJECT_PATH_NOT_FOUND, got %08x\n", status ); + + nameW.Length = 0; + nameW.Buffer = NULL; + attr.RootDirectory = file; + attr.ObjectName = &nameW; + status = pNtOpenFile( &root, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); + ok( !status, "open %s failed %x\n", wine_dbgstr_w(tmpfile), status ); + + numbytes = SetFilePointer( file, 0, 0, FILE_CURRENT ); + ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes ); + numbytes = SetFilePointer( root, 0, 0, FILE_CURRENT ); + ok( numbytes == 0, "SetFilePointer returned %u\n", numbytes ); + + numbytes = 0xdeadbeef; + memset( data, 0, sizeof(data) ); + ret = ReadFile( root, data, sizeof(data), &numbytes, NULL ); + ok( ret, "ReadFile failed with error %u\n", GetLastError() ); + ok( numbytes == sizeof(testdata) - 1, "failed to read all data\n" ); + ok( !memcmp( data, testdata, sizeof(testdata) - 1 ), "testdata doesn't match\n" ); + + numbytes = SetFilePointer( file, 0, 0, FILE_CURRENT ); + ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes ); + numbytes = SetFilePointer( root, 0, 0, FILE_CURRENT ); + ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes ); + + CloseHandle( file ); + CloseHandle( root ); + DeleteFileW( tmpfile ); } static void delete_file_test(void) @@ -1428,6 +1568,1279 @@ static void test_file_all_information(void) CloseHandle( h ); } +static void delete_object( WCHAR *path ) +{ + BOOL ret = DeleteFileW( path ); + ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED, + "DeleteFileW failed with %u\n", GetLastError() ); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + ret = RemoveDirectoryW( path ); + ok( ret, "RemoveDirectoryW failed with %u\n", GetLastError() ); + } +} + +static void test_file_rename_information(void) +{ + static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0}; + static const WCHAR fooW[] = {'f','o','o',0}; + WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p; + FILE_RENAME_INFORMATION *fri; + FILE_NAME_INFORMATION *fni; + BOOL success, fileDeleted; + UNICODE_STRING name_str; + HANDLE handle, handle2; + IO_STATUS_BLOCK io; + NTSTATUS res; + + GetTempPathW( MAX_PATH, tmp_path ); + + /* oldpath is a file, newpath doesn't exist */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + DeleteFileW( newpath ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", + wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, Replace = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, Replace = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, Replace = FALSE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, Replace = TRUE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath doesn't exist, Replace = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + DeleteFileW( newpath ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", + wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory (but child object opened), newpath doesn't exist, Replace = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + lstrcpyW( newpath, oldpath ); + lstrcatW( newpath, foo_txtW ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + DeleteFileW( newpath ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + todo_wine ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + todo_wine ok( fileDeleted, "file should not exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + if (res == STATUS_SUCCESS) /* remove when Wine is fixed */ + { + lstrcpyW( oldpath, newpath ); + lstrcatW( oldpath, foo_txtW ); + delete_object( oldpath ); + } + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, Replace = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, Replace = FALSE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, Replace = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, Replace = TRUE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, Replace = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, Replace = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, Replace = TRUE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a directory, Replace = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = FALSE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a directory, Replace = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Replace = TRUE; + fri->RootDir = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath doesn't exist, test with RootDir != NULL */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + for (filename = newpath, p = newpath; *p; p++) + if (*p == '\\') filename = p + 1; + handle2 = CreateFileW( tmp_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + lstrlenW(filename) * sizeof(WCHAR) ); + fri->Replace = FALSE; + fri->RootDir = handle2; + fri->FileNameLength = lstrlenW(filename) * sizeof(WCHAR); + memcpy( fri->FileName, filename, fri->FileNameLength ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", + wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); +} + +static void test_file_link_information(void) +{ + static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0}; + static const WCHAR fooW[] = {'f','o','o',0}; + WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p; + FILE_LINK_INFORMATION *fli; + FILE_NAME_INFORMATION *fni; + BOOL success, fileDeleted; + UNICODE_STRING name_str; + HANDLE handle, handle2; + IO_STATUS_BLOCK io; + NTSTATUS res; + + GetTempPathW( MAX_PATH, tmp_path ); + + /* oldpath is a file, newpath doesn't exist */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + DeleteFileW( newpath ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", + wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, ReplaceIfExists = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, ReplaceIfExists = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, ReplaceIfExists = FALSE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, ReplaceIfExists = TRUE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath doesn't exist, ReplaceIfExists = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + DeleteFileW( newpath ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef , "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", + wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory (but child object opened), newpath doesn't exist, ReplaceIfExists = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + lstrcpyW( newpath, oldpath ); + lstrcatW( newpath, foo_txtW ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + DeleteFileW( newpath ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, ReplaceIfExists = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */, + "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, ReplaceIfExists = FALSE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */, + "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, ReplaceIfExists = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, ReplaceIfExists = TRUE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, ReplaceIfExists = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */, + "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, ReplaceIfExists = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, ReplaceIfExists = TRUE, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a directory, ReplaceIfExists = FALSE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a directory, ReplaceIfExists = TRUE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->ReplaceIfExists = TRUE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath doesn't exist, test with RootDirectory != NULL */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + for (filename = newpath, p = newpath; *p; p++) + if (*p == '\\') filename = p + 1; + handle2 = CreateFileW( tmp_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + lstrlenW(filename) * sizeof(WCHAR) ); + fli->ReplaceIfExists = FALSE; + fli->RootDirectory = handle2; + fli->FileNameLength = lstrlenW(filename) * sizeof(WCHAR); + memcpy( fli->FileName, filename, fli->FileNameLength ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); + ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); + res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); + fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; + ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", + wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); + HeapFree( GetProcessHeap(), 0, fni ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); +} + static void test_file_both_information(void) { IO_STATUS_BLOCK io; @@ -1453,10 +2866,26 @@ static void test_file_disposition_information(void) IO_STATUS_BLOCK io; FILE_DISPOSITION_INFORMATION fdi; BOOL fileDeleted; + DWORD fdi2; void *ptr; GetTempPathA( MAX_PATH, tmp_path ); + /* tests for info struct size */ + GetTempFileNameA( tmp_path, "dis", 0, buffer ); + handle = CreateFileA( buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + res = pNtSetInformationFile( handle, &io, &fdi, 0, FileDispositionInformation ); + todo_wine + ok( res == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %x\n", res ); + fdi2 = 0x100; + res = pNtSetInformationFile( handle, &io, &fdi2, sizeof(fdi2), FileDispositionInformation ); + ok( res == STATUS_SUCCESS, "expected STATUS_SUCCESS, 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" ); + DeleteFileA( buffer ); + /* cannot set disposition on file not opened with delete access */ GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); @@ -1512,20 +2941,6 @@ static void test_file_disposition_information(void) 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 ); - /* can set disposition on file and then reset it */ GetTempFileNameA( tmp_path, "dis", 0, buffer ); handle = CreateFileA(buffer, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0); @@ -2000,11 +3415,11 @@ static void test_query_volume_information_file(void) ffvi = (FILE_FS_VOLUME_INFORMATION *)buf; -todo_wine -{ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", status); ok(U(io).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", U(io).Status); +todo_wine +{ ok(io.Information == (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength), "expected %d, got %lu\n", (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength), io.Information); @@ -2153,6 +3568,83 @@ static void test_NtCreateFile(void) DeleteFileW( path ); } +static void test_readonly(void) +{ + static const WCHAR fooW[] = {'f','o','o',0}; + NTSTATUS status; + HANDLE handle; + WCHAR path[MAX_PATH]; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + UNICODE_STRING nameW; + + GetTempPathW(MAX_PATH, path); + GetTempFileNameW(path, fooW, 0, path); + DeleteFileW(path); + pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL); + + attr.Length = sizeof(attr); + attr.RootDirectory = NULL; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = pNtCreateFile(&handle, GENERIC_READ, &attr, &io, NULL, FILE_ATTRIBUTE_READONLY, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_CREATE, 0, NULL, 0); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, GENERIC_WRITE, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_ACCESS_DENIED, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, FILE_READ_ATTRIBUTES, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, FILE_WRITE_ATTRIBUTES, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, DELETE, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, READ_CONTROL, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, WRITE_DAC, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, WRITE_OWNER, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle( handle ); + + pRtlFreeUnicodeString(&nameW); + SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE); + DeleteFileW(path); +} + static void test_read_write(void) { static const char contents[14] = "1234567890abcd"; @@ -2865,6 +4357,86 @@ static void test_read_write(void) CloseHandle(hfile); } +static void test_query_ea(void) +{ + #define EA_BUFFER_SIZE 4097 + unsigned char data[EA_BUFFER_SIZE + 8]; + unsigned char *buffer = (void *)(((DWORD_PTR)data + 7) & ~7); + DWORD buffer_len, i; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE handle; + + if (!(handle = create_temp_file(0))) return; + + /* test with INVALID_HANDLE_VALUE */ + U(io).Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset(buffer, 0xcc, EA_BUFFER_SIZE); + buffer_len = EA_BUFFER_SIZE - 1; + status = pNtQueryEaFile(INVALID_HANDLE_VALUE, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE); + ok(status == STATUS_OBJECT_TYPE_MISMATCH, "expected STATUS_OBJECT_TYPE_MISMATCH, got %x\n", status); + ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status); + ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information); + ok(buffer[0] == 0xcc, "data at position 0 overwritten\n"); + + /* test with 0xdeadbeef */ + U(io).Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset(buffer, 0xcc, EA_BUFFER_SIZE); + buffer_len = EA_BUFFER_SIZE - 1; + status = pNtQueryEaFile((void *)0xdeadbeef, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %x\n", status); + ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status); + ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information); + ok(buffer[0] == 0xcc, "data at position 0 overwritten\n"); + + /* test without buffer */ + U(io).Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + status = pNtQueryEaFile(handle, &io, NULL, 0, TRUE, NULL, 0, NULL, FALSE); + ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status); + ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status); + ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information); + + /* test with zero buffer */ + U(io).Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + status = pNtQueryEaFile(handle, &io, buffer, 0, TRUE, NULL, 0, NULL, FALSE); + ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status); + ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status); + ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information); + + /* test with very small buffer */ + U(io).Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset(buffer, 0xcc, EA_BUFFER_SIZE); + buffer_len = 4; + status = pNtQueryEaFile(handle, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE); + ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status); + ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status); + ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information); + for (i = 0; i < buffer_len && !buffer[i]; i++); + ok(i == buffer_len, "expected %u bytes filled with 0x00, got %u bytes\n", buffer_len, i); + ok(buffer[i] == 0xcc, "data at position %u overwritten\n", buffer[i]); + + /* test with very big buffer */ + U(io).Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset(buffer, 0xcc, EA_BUFFER_SIZE); + buffer_len = EA_BUFFER_SIZE - 1; + status = pNtQueryEaFile(handle, &io, buffer, buffer_len, TRUE, NULL, 0, NULL, FALSE); + ok(status == STATUS_NO_EAS_ON_FILE, "expected STATUS_NO_EAS_ON_FILE, got %x\n", status); + ok(U(io).Status == 0xdeadbeef, "expected 0xdeadbeef, got %x\n", U(io).Status); + ok(io.Information == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", io.Information); + for (i = 0; i < buffer_len && !buffer[i]; i++); + ok(i == buffer_len, "expected %u bytes filled with 0x00, got %u bytes\n", buffer_len, i); + ok(buffer[i] == 0xcc, "data at position %u overwritten\n", buffer[i]); + + CloseHandle(handle); + #undef EA_BUFFER_SIZE +} + static INT build_reparse_buffer(WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer) { REPARSE_DATA_BUFFER *buffer; @@ -3072,9 +4644,12 @@ START_TEST(file) pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll, "NtQueryVolumeInformationFile"); + pNtQueryFullAttributesFile = (void *)GetProcAddress(hntdll, "NtQueryFullAttributesFile"); + pNtQueryEaFile = (void *)GetProcAddress(hntdll, "NtQueryEaFile"); test_read_write(); test_NtCreateFile(); + test_readonly(); create_file_test(); open_file_test(); delete_file_test(); @@ -3088,8 +4663,11 @@ START_TEST(file) test_file_name_information(); test_file_full_size_information(); test_file_all_name_information(); + test_file_rename_information(); + test_file_link_information(); test_file_disposition_information(); test_query_volume_information_file(); test_query_attribute_information_file(); + test_query_ea(); test_junction_points(); } diff --git a/rostests/winetests/ntdll/generated.c b/rostests/winetests/ntdll/generated.c index f8ef346c776..b099a5c0848 100755 --- a/rostests/winetests/ntdll/generated.c +++ b/rostests/winetests/ntdll/generated.c @@ -839,72 +839,142 @@ static void test_pack_IMAGE_LINENUMBER(void) static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY(void) { /* IMAGE_LOAD_CONFIG_DIRECTORY */ -#ifndef __REACTOS__ - TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, 88) -#endif + TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, 112) TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, 8) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, Size, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, Size, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Size, 0) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 8) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 10) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 12) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 16) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 20) -#ifndef __REACTOS__ // wine headers are broken - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 24) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 28) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 8) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 8) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 32) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 40) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 44) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 48) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 52) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 56) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 58) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 8) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 8) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 64) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 72) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 76) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 80) -#endif +} + +static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY32(void) +{ + /* IMAGE_LOAD_CONFIG_DIRECTORY32 */ + TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, 88) + TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, Size, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, Size, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, Size, 0) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsClear, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsClear, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsClear, 12) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsSet, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsSet, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsSet, 16) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, CriticalSectionDefaultTimeout, 20) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold, 24) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitTotalFreeThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitTotalFreeThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitTotalFreeThreshold, 28) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, LockPrefixTable, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, LockPrefixTable, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, LockPrefixTable, 32) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, MaximumAllocationSize, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, MaximumAllocationSize, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, MaximumAllocationSize, 40) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, VirtualMemoryThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, VirtualMemoryThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, VirtualMemoryThreshold, 44) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessHeapFlags, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessHeapFlags, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessHeapFlags, 48) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessAffinityMask, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessAffinityMask, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessAffinityMask, 52) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, CSDVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, CSDVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, CSDVersion, 56) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, Reserved1, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, Reserved1, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, Reserved1, 58) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, EditList, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, EditList, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, EditList, 64) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, SecurityCookie, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, SecurityCookie, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SecurityCookie, 72) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable, 76) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount, 80) +} + +static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY64(void) +{ + /* IMAGE_LOAD_CONFIG_DIRECTORY64 */ + TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, 112) + TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, Size, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, Size, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, Size, 0) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsClear, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsClear, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsClear, 12) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsSet, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsSet, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsSet, 16) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, CriticalSectionDefaultTimeout, 20) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold, 24) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitTotalFreeThreshold, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitTotalFreeThreshold, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitTotalFreeThreshold, 32) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, LockPrefixTable, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, LockPrefixTable, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, LockPrefixTable, 40) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, MaximumAllocationSize, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, MaximumAllocationSize, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, MaximumAllocationSize, 48) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, VirtualMemoryThreshold, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, VirtualMemoryThreshold, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, VirtualMemoryThreshold, 56) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessAffinityMask, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessAffinityMask, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessAffinityMask, 64) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessHeapFlags, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessHeapFlags, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessHeapFlags, 72) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, CSDVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, CSDVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, CSDVersion, 76) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, Reserved1, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, Reserved1, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, Reserved1, 78) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, EditList, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, EditList, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, EditList, 80) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, SecurityCookie, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, SecurityCookie, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SecurityCookie, 88) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable, 96) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerCount, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerCount, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerCount, 104) } static void test_pack_IMAGE_NT_HEADERS(void) @@ -2109,10 +2179,6 @@ static void test_pack_PIMAGE_LOAD_CONFIG_DIRECTORY(void) /* PIMAGE_LOAD_CONFIG_DIRECTORY */ TEST_TYPE_SIZE (PIMAGE_LOAD_CONFIG_DIRECTORY, 8) TEST_TYPE_ALIGN (PIMAGE_LOAD_CONFIG_DIRECTORY, 8) -#ifndef __REACTOS__ // wine headers are broken - TEST_TARGET_SIZE (PIMAGE_LOAD_CONFIG_DIRECTORY, 88) -#endif - TEST_TARGET_ALIGN(PIMAGE_LOAD_CONFIG_DIRECTORY, 8) } static void test_pack_PIMAGE_NT_HEADERS(void) @@ -4192,66 +4258,140 @@ static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY(void) /* IMAGE_LOAD_CONFIG_DIRECTORY */ TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, 72) TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, 4) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, Size, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, Size, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Size, 0) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, TimeDateStamp, 4) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MajorVersion, 8) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MinorVersion, 10) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsClear, 12) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, GlobalFlagsSet, 16) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, CriticalSectionDefaultTimeout, 20) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitFreeBlockThreshold, 24) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, DeCommitTotalFreeThreshold, 28) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, LockPrefixTable, 32) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, MaximumAllocationSize, 36) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, VirtualMemoryThreshold, 40) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessHeapFlags, 44) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, ProcessAffinityMask, 48) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, CSDVersion, 52) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 2) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 2) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, Reserved1, 54) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, EditList, 56) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie, 60) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerTable, 64) - TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 4) - TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 4) - TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY, SEHandlerCount, 68) +} + +static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY32(void) +{ + /* IMAGE_LOAD_CONFIG_DIRECTORY32 */ + TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, 72) + TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, Size, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, Size, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, Size, 0) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsClear, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsClear, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsClear, 12) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsSet, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsSet, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, GlobalFlagsSet, 16) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, CriticalSectionDefaultTimeout, 20) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold, 24) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitTotalFreeThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitTotalFreeThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitTotalFreeThreshold, 28) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, LockPrefixTable, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, LockPrefixTable, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, LockPrefixTable, 32) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, MaximumAllocationSize, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, MaximumAllocationSize, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, MaximumAllocationSize, 36) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, VirtualMemoryThreshold, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, VirtualMemoryThreshold, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, VirtualMemoryThreshold, 40) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessHeapFlags, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessHeapFlags, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessHeapFlags, 44) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessAffinityMask, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessAffinityMask, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, ProcessAffinityMask, 48) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, CSDVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, CSDVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, CSDVersion, 52) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, Reserved1, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, Reserved1, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, Reserved1, 54) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, EditList, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, EditList, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, EditList, 56) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, SecurityCookie, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, SecurityCookie, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SecurityCookie, 60) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable, 64) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount, 68) +} + +static void test_pack_IMAGE_LOAD_CONFIG_DIRECTORY64(void) +{ + /* IMAGE_LOAD_CONFIG_DIRECTORY64 */ + TEST_TYPE_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, 112) + TEST_TYPE_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, Size, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, Size, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, Size, 0) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, TimeDateStamp, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, TimeDateStamp, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, TimeDateStamp, 4) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, MajorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, MajorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, MajorVersion, 8) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, MinorVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, MinorVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, MinorVersion, 10) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsClear, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsClear, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsClear, 12) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsSet, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsSet, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, GlobalFlagsSet, 16) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, CriticalSectionDefaultTimeout, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, CriticalSectionDefaultTimeout, 20) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold, 24) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitTotalFreeThreshold, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitTotalFreeThreshold, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitTotalFreeThreshold, 32) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, LockPrefixTable, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, LockPrefixTable, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, LockPrefixTable, 40) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, MaximumAllocationSize, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, MaximumAllocationSize, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, MaximumAllocationSize, 48) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, VirtualMemoryThreshold, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, VirtualMemoryThreshold, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, VirtualMemoryThreshold, 56) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessAffinityMask, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessAffinityMask, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessAffinityMask, 64) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessHeapFlags, 4) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessHeapFlags, 4) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, ProcessHeapFlags, 72) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, CSDVersion, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, CSDVersion, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, CSDVersion, 76) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, Reserved1, 2) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, Reserved1, 2) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, Reserved1, 78) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, EditList, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, EditList, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, EditList, 80) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, SecurityCookie, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, SecurityCookie, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SecurityCookie, 88) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable, 96) + TEST_FIELD_SIZE (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerCount, 8) + TEST_FIELD_ALIGN (IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerCount, 8) + TEST_FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerCount, 104) } static void test_pack_IMAGE_NT_HEADERS(void) @@ -5456,8 +5596,6 @@ static void test_pack_PIMAGE_LOAD_CONFIG_DIRECTORY(void) /* PIMAGE_LOAD_CONFIG_DIRECTORY */ TEST_TYPE_SIZE (PIMAGE_LOAD_CONFIG_DIRECTORY, 4) TEST_TYPE_ALIGN (PIMAGE_LOAD_CONFIG_DIRECTORY, 4) - TEST_TARGET_SIZE (PIMAGE_LOAD_CONFIG_DIRECTORY, 72) - TEST_TARGET_ALIGN(PIMAGE_LOAD_CONFIG_DIRECTORY, 4) } static void test_pack_PIMAGE_NT_HEADERS(void) @@ -6828,6 +6966,8 @@ static void test_pack(void) test_pack_IMAGE_IMPORT_DESCRIPTOR(); test_pack_IMAGE_LINENUMBER(); test_pack_IMAGE_LOAD_CONFIG_DIRECTORY(); + test_pack_IMAGE_LOAD_CONFIG_DIRECTORY32(); + test_pack_IMAGE_LOAD_CONFIG_DIRECTORY64(); test_pack_IMAGE_NT_HEADERS(); test_pack_IMAGE_NT_HEADERS32(); test_pack_IMAGE_NT_HEADERS64(); diff --git a/rostests/winetests/ntdll/info.c b/rostests/winetests/ntdll/info.c index 5fff4908683..c0e2b1ac5d4 100755 --- a/rostests/winetests/ntdll/info.c +++ b/rostests/winetests/ntdll/info.c @@ -477,27 +477,47 @@ static void test_query_handle(void) ULONG ReturnLength; ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION); SYSTEM_HANDLE_INFORMATION* shi = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength); + HANDLE event_handle; + + event_handle = CreateEventA(NULL, FALSE, FALSE, NULL); + ok( event_handle != NULL, "CreateEventA failed %u\n", GetLastError() ); /* Request the needed length : a SystemInformationLength greater than one struct sets ReturnLength */ + ReturnLength = 0xdeadbeef; status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); - todo_wine ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( ReturnLength != 0xdeadbeef, "Expected valid ReturnLength\n" ); SystemInformationLength = ReturnLength; shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength); + + ReturnLength = 0xdeadbeef; status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); if (status != STATUS_INFO_LENGTH_MISMATCH) /* vista */ { - ok( status == STATUS_SUCCESS, - "Expected STATUS_SUCCESS, got %08x\n", status); + ULONG ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]); + unsigned int i; + BOOL found = FALSE; - /* Check if we have some return values */ - trace("Number of Handles : %d\n", shi->Count); - todo_wine + ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); + ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); + ok( shi->Count > 1, "Expected more than 1 handles, got %u\n", shi->Count ); + for (i = 0; i < shi->Count; i++) { - /* our implementation is a stub for now */ - ok( shi->Count > 1, "Expected more than 1 handles, got (%d)\n", shi->Count); + if (shi->Handle[i].OwnerPid == GetCurrentProcessId() && + (HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == event_handle) + { + found = TRUE; + break; + } } + ok( found, "Expected to find event handle in handle list\n" ); } + + status = pNtQuerySystemInformation(SystemHandleInformation, NULL, SystemInformationLength, &ReturnLength); + ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status ); + + CloseHandle(event_handle); HeapFree( GetProcessHeap(), 0, shi); } @@ -1442,6 +1462,8 @@ static void test_mapprotection(void) *(unsigned char*)addr = 0xc3; /* lret ... in both i386 and x86_64 */ #elif defined(__arm__) *(unsigned long*)addr = 0xe12fff1e; /* bx lr */ +#elif defined(__aarch64__) + *(unsigned long*)addr = 0xd65f03c0; /* ret */ #else ok(0, "Add a return opcode for your architecture or expect a crash in this test\n"); #endif @@ -1695,6 +1717,69 @@ static void test_NtGetCurrentProcessorNumber(void) ok(status == STATUS_SUCCESS, "got 0x%x (expected STATUS_SUCCESS)\n", status); } +static DWORD WINAPI start_address_thread(void *arg) +{ + PRTL_THREAD_START_ROUTINE entry; + NTSTATUS status; + DWORD ret; + + entry = NULL; + ret = 0xdeadbeef; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadQuerySetWin32StartAddress, + &entry, sizeof(entry), &ret); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok(ret == sizeof(entry), "NtQueryInformationThread returned %u bytes\n", ret); + ok(entry == (void *)start_address_thread, "expected %p, got %p\n", start_address_thread, entry); + return 0; +} + +static void test_thread_start_address(void) +{ + PRTL_THREAD_START_ROUTINE entry, expected_entry; + IMAGE_NT_HEADERS *nt; + NTSTATUS status; + HANDLE thread; + void *module; + DWORD ret; + + module = GetModuleHandleA(0); + ok(module != NULL, "expected non-NULL address for module\n"); + nt = RtlImageNtHeader(module); + ok(nt != NULL, "expected non-NULL address for NT header\n"); + + entry = NULL; + ret = 0xdeadbeef; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadQuerySetWin32StartAddress, + &entry, sizeof(entry), &ret); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok(ret == sizeof(entry), "NtQueryInformationThread returned %u bytes\n", ret); + expected_entry = (void *)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); + ok(entry == expected_entry, "expected %p, got %p\n", expected_entry, entry); + + entry = (void *)0xdeadbeef; + status = pNtSetInformationThread(GetCurrentThread(), ThreadQuerySetWin32StartAddress, + &entry, sizeof(entry)); + ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER, /* >= Vista */ + "expected STATUS_SUCCESS or STATUS_INVALID_PARAMETER, got %08x\n", status); + + if (status == STATUS_SUCCESS) + { + entry = NULL; + ret = 0xdeadbeef; + status = pNtQueryInformationThread(GetCurrentThread(), ThreadQuerySetWin32StartAddress, + &entry, sizeof(entry), &ret); + ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); + ok(ret == sizeof(entry), "NtQueryInformationThread returned %u bytes\n", ret); + ok(entry == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", entry); + } + + thread = CreateThread(NULL, 0, start_address_thread, NULL, 0, NULL); + ok(thread != INVALID_HANDLE_VALUE, "CreateThread failed with %d\n", GetLastError()); + ret = WaitForSingleObject(thread, 1000); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret); + CloseHandle(thread); +} + START_TEST(info) { char **argv; @@ -1820,5 +1905,10 @@ START_TEST(info) trace("Starting test_affinity()\n"); test_affinity(); + + trace("Starting test_NtGetCurrentProcessorNumber()\n"); test_NtGetCurrentProcessorNumber(); + + trace("Starting test_thread_start_address()\n"); + test_thread_start_address(); } diff --git a/rostests/winetests/ntdll/om.c b/rostests/winetests/ntdll/om.c index 83b63d86894..65e9260a1e5 100644 --- a/rostests/winetests/ntdll/om.c +++ b/rostests/winetests/ntdll/om.c @@ -54,6 +54,7 @@ static NTSTATUS (WINAPI *pNtCreateKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJE static NTSTATUS (WINAPI *pNtOpenKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES * ); static NTSTATUS (WINAPI *pNtWaitForKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); +static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); #define KEYEDEVENT_WAIT 0x0001 #define KEYEDEVENT_WAKE 0x0002 @@ -150,7 +151,7 @@ static void test_namespace_pipe(void) pRtlInitUnicodeString(&str, buffer3); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); - status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); + status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0); ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_PIPE_NOT_AVAILABLE || status == STATUS_OBJECT_NAME_INVALID || /* vista */ @@ -159,7 +160,7 @@ static void test_namespace_pipe(void) pRtlInitUnicodeString(&str, buffer4); InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); - status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); + status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0); ok(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_NAME_INVALID, /* vista */ "NtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND got(%08x)\n", status); @@ -657,8 +658,10 @@ static void test_symboliclink(void) pRtlFreeUnicodeString(&target); pRtlCreateUnicodeStringFromAsciiz(&str, "test-link\\NUL"); - status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - todo_wine ok(status == STATUS_SUCCESS, "Failed to open NUL device(%08x)\n", status); + status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, 0); + ok(status == STATUS_SUCCESS, "Failed to open NUL device(%08x)\n", status); + status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE); + ok(status == STATUS_SUCCESS, "Failed to open NUL device(%08x)\n", status); pRtlFreeUnicodeString(&str); pNtClose(h); @@ -672,12 +675,16 @@ static void test_query_object(void) '\\','t','e','s','t','_','e','v','e','n','t'}; static const WCHAR type_event[] = {'E','v','e','n','t'}; static const WCHAR type_file[] = {'F','i','l','e'}; + static const WCHAR type_iocompletion[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; + static const WCHAR type_directory[] = {'D','i','r','e','c','t','o','r','y'}; + static const WCHAR type_section[] = {'S','e','c','t','i','o','n'}; HANDLE handle; char buffer[1024]; NTSTATUS status; ULONG len, expected_len; UNICODE_STRING *str; - char dir[MAX_PATH]; + char dir[MAX_PATH], tmp_path[MAX_PATH], file1[MAX_PATH + 16]; + LARGE_INTEGER size; handle = CreateEventA( NULL, FALSE, FALSE, "test_event" ); @@ -784,6 +791,66 @@ static void test_query_object(void) "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); pNtClose( handle ); + + GetTempPathA(MAX_PATH, tmp_path); + GetTempFileNameA(tmp_path, "foo", 0, file1); + handle = CreateFileA(file1, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0); + len = 0; + memset( buffer, 0, sizeof(buffer) ); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(OBJECT_TYPE_INFORMATION), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(OBJECT_TYPE_INFORMATION) + str->Length + sizeof(WCHAR); + ok( len >= expected_len, "unexpected len %u\n", len ); + ok( str->Buffer && !memcmp( str->Buffer, type_file, sizeof(type_file) ), + "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); + DeleteFileA( file1 ); + pNtClose( handle ); + + status = pNtCreateIoCompletion( &handle, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); + ok( status == STATUS_SUCCESS, "NtCreateIoCompletion failed %x\n", status); + len = 0; + memset( buffer, 0, sizeof(buffer) ); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(OBJECT_TYPE_INFORMATION), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(OBJECT_TYPE_INFORMATION) + str->Length + sizeof(WCHAR); + ok( len >= expected_len, "unexpected len %u\n", len ); + ok( str->Buffer && !memcmp( str->Buffer, type_iocompletion, sizeof(type_iocompletion) ), + "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); + pNtClose( handle ); + + status = pNtCreateDirectoryObject( &handle, DIRECTORY_QUERY, NULL ); + ok(status == STATUS_SUCCESS, "Failed to create Directory %08x\n", status); + len = 0; + memset( buffer, 0, sizeof(buffer) ); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(OBJECT_TYPE_INFORMATION), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(OBJECT_TYPE_INFORMATION) + str->Length + sizeof(WCHAR); + ok( len >= expected_len, "unexpected len %u\n", len ); + ok( str->Buffer && !memcmp( str->Buffer, type_directory, sizeof(type_directory) ), + "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); + pNtClose( handle ); + + size.u.LowPart = 256; + size.u.HighPart = 0; + status = pNtCreateSection( &handle, SECTION_MAP_WRITE, NULL, &size, PAGE_READWRITE, SEC_COMMIT, 0 ); + ok( status == STATUS_SUCCESS , "NtCreateSection returned %x\n", status ); + len = 0; + memset( buffer, 0, sizeof(buffer) ); + status = pNtQueryObject( handle, ObjectTypeInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(OBJECT_TYPE_INFORMATION), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + expected_len = sizeof(OBJECT_TYPE_INFORMATION) + str->Length + sizeof(WCHAR); + ok( len >= expected_len, "unexpected len %u\n", len ); + ok( str->Buffer && !memcmp( str->Buffer, type_section, sizeof(type_section) ), + "wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer ); + pNtClose( handle ); } static void test_type_mismatch(void) @@ -1055,23 +1122,19 @@ static void test_null_device(void) "expected STATUS_OBJECT_TYPE_MISMATCH, got %08x\n", status); status = pNtOpenFile(&null, GENERIC_READ | GENERIC_WRITE, &attr, &iosb, - FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN); + FILE_SHARE_READ | FILE_SHARE_WRITE, 0); ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); SetLastError(0xdeadbeef); ret = WriteFile(null, buf, sizeof(buf), &num_bytes, NULL); - todo_wine ok(!ret, "WriteFile unexpectedly succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); SetLastError(0xdeadbeef); ret = ReadFile(null, buf, sizeof(buf), &num_bytes, NULL); - todo_wine ok(!ret, "ReadFile unexpectedly succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError()); @@ -1166,6 +1229,7 @@ START_TEST(om) pNtOpenKeyedEvent = (void *)GetProcAddress(hntdll, "NtOpenKeyedEvent"); pNtWaitForKeyedEvent = (void *)GetProcAddress(hntdll, "NtWaitForKeyedEvent"); pNtReleaseKeyedEvent = (void *)GetProcAddress(hntdll, "NtReleaseKeyedEvent"); + pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); test_case_sensitive(); test_namespace_pipe(); diff --git a/rostests/winetests/ntdll/reg.c b/rostests/winetests/ntdll/reg.c index 5fc86b5f754..8984e243eb5 100755 --- a/rostests/winetests/ntdll/reg.c +++ b/rostests/winetests/ntdll/reg.c @@ -123,6 +123,7 @@ static NTSTATUS (WINAPI * pRtlQueryRegistryValues)(IN ULONG, IN PCWSTR,IN PRTL_Q static NTSTATUS (WINAPI * pRtlCheckRegistryKey)(IN ULONG,IN PWSTR); static NTSTATUS (WINAPI * pRtlOpenCurrentUser)(IN ACCESS_MASK, PHANDLE); static NTSTATUS (WINAPI * pNtOpenKey)(PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES); +static NTSTATUS (WINAPI * pNtOpenKeyEx)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); static NTSTATUS (WINAPI * pNtClose)(IN HANDLE); static NTSTATUS (WINAPI * pNtFlushKey)(HANDLE); static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE); @@ -145,6 +146,10 @@ static NTSTATUS (WINAPI * pRtlFreeHeap)(PVOID, ULONG, PVOID); static LPVOID (WINAPI * pRtlAllocateHeap)(PVOID,ULONG,ULONG); static NTSTATUS (WINAPI * pRtlZeroMemory)(PVOID, ULONG); static NTSTATUS (WINAPI * pRtlpNtQueryValueKey)(HANDLE,ULONG*,PBYTE,DWORD*,void *); +static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN); +static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE, + void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN); +static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*); static HMODULE hntdll = 0; static int CurrentTest = 0; @@ -182,6 +187,7 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(NtQueryInformationProcess) NTDLL_GET_PROC(NtSetValueKey) NTDLL_GET_PROC(NtOpenKey) + NTDLL_GET_PROC(NtNotifyChangeKey) NTDLL_GET_PROC(RtlFormatCurrentUserKeyPath) NTDLL_GET_PROC(RtlCompareUnicodeString) NTDLL_GET_PROC(RtlReAllocateHeap) @@ -192,9 +198,12 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(RtlZeroMemory) NTDLL_GET_PROC(RtlpNtQueryValueKey) NTDLL_GET_PROC(RtlOpenCurrentUser) + NTDLL_GET_PROC(NtWaitForSingleObject) /* optional functions */ pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue"); + pNtOpenKeyEx = (void *)GetProcAddress(hntdll, "NtOpenKeyEx"); + pNtNotifyChangeMultipleKeys = (void *)GetProcAddress(hntdll, "NtNotifyChangeMultipleKeys"); return TRUE; } @@ -351,6 +360,18 @@ static void test_NtOpenKey(void) attr.Length *= 2; status = pNtOpenKey(&key, am, &attr); ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got: 0x%08x\n", status); + + if (!pNtOpenKeyEx) + { + win_skip("NtOpenKeyEx not available\n"); + return; + } + + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); + status = pNtOpenKeyEx(&key, KEY_WRITE|KEY_READ, &attr, 0); + ok(status == STATUS_SUCCESS, "NtOpenKeyEx Failed: 0x%08x\n", status); + + pNtClose(key); } static void test_NtCreateKey(void) @@ -509,14 +530,14 @@ static void test_NtQueryValueKey(void) OBJECT_ATTRIBUTES attr; UNICODE_STRING ValName; KEY_VALUE_BASIC_INFORMATION *basic_info; - KEY_VALUE_PARTIAL_INFORMATION *partial_info; + KEY_VALUE_PARTIAL_INFORMATION *partial_info, pi; KEY_VALUE_FULL_INFORMATION *full_info; DWORD len, expected; pRtlCreateUnicodeStringFromAsciiz(&ValName, "deletetest"); InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); - status = pNtOpenKey(&key, KEY_READ, &attr); + status = pNtOpenKey(&key, KEY_READ|KEY_SET_VALUE, &attr); ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); len = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]); @@ -611,8 +632,18 @@ static void test_NtQueryValueKey(void) ok(len == expected, "NtQueryValueKey wrong len %u\n", len); HeapFree(GetProcessHeap(), 0, partial_info); - pRtlFreeUnicodeString(&ValName); + + pRtlCreateUnicodeStringFromAsciiz(&ValName, "custtest"); + status = pNtSetValueKey(key, &ValName, 0, 0xff00ff00, NULL, 0); + ok(status == STATUS_SUCCESS, "NtSetValueKey Failed: 0x%08x\n", status); + + status = pNtQueryValueKey(key, &ValName, KeyValuePartialInformation, &pi, sizeof(pi), &len); + ok(status == STATUS_SUCCESS, "NtQueryValueKey should have returned STATUS_BUFFER_TOO_SMALL instead of 0x%08x\n", status); + ok(pi.Type == 0xff00ff00, "Type=%x\n", pi.Type); + ok(pi.DataLength == 0, "DataLength=%u\n", pi.DataLength); + pRtlFreeUnicodeString(&ValName); + pNtClose(key); } @@ -1445,12 +1476,14 @@ static void test_long_value_name(void) static void test_NtQueryKey(void) { - HANDLE key; + HANDLE key, subkey, subkey2; NTSTATUS status; OBJECT_ATTRIBUTES attr; ULONG length, len; KEY_NAME_INFORMATION *info = NULL; + KEY_CACHED_INFORMATION cached_info; UNICODE_STRING str; + DWORD dw; InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); status = pNtOpenKey(&key, KEY_READ, &attr); @@ -1485,9 +1518,171 @@ static void test_NtQueryKey(void) wine_dbgstr_wn(winetestpath.Buffer, winetestpath.Length/sizeof(WCHAR))); HeapFree(GetProcessHeap(), 0, info); + + attr.RootDirectory = key; + attr.ObjectName = &str; + pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); + status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); + + status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); + + if (status == STATUS_SUCCESS) + { + ok(len == sizeof(cached_info), "got unexpected length %d\n", len); + ok(cached_info.SubKeys == 0, "cached_info.SubKeys = %u\n", cached_info.SubKeys); + ok(cached_info.MaxNameLen == 0, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen); + ok(cached_info.Values == 0, "cached_info.Values = %u\n", cached_info.Values); + ok(cached_info.MaxValueNameLen == 0, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen); + ok(cached_info.MaxValueDataLen == 0, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen); + ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength); + } + + attr.RootDirectory = subkey; + attr.ObjectName = &str; + pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey2"); + status = pNtCreateKey(&subkey2, GENERIC_ALL, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); + + pRtlCreateUnicodeStringFromAsciiz(&str, "val"); + dw = 64; + status = pNtSetValueKey( subkey, &str, 0, REG_DWORD, &dw, sizeof(dw) ); + ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08x\n", status ); + + if (!winetest_interactive) + skip("ROSTESTS-198: Causes an assert in Cm.\n"); + else + { + status = pNtQueryKey(subkey, KeyCachedInformation, &cached_info, sizeof(cached_info), &len); + ok(status == STATUS_SUCCESS, "NtQueryKey Failed: 0x%08x\n", status); + + if (status == STATUS_SUCCESS) + { + ok(len == sizeof(cached_info), "got unexpected length %d\n", len); + ok(cached_info.SubKeys == 1, "cached_info.SubKeys = %u\n", cached_info.SubKeys); + ok(cached_info.MaxNameLen == 24, "cached_info.MaxNameLen = %u\n", cached_info.MaxNameLen); + ok(cached_info.Values == 1, "cached_info.Values = %u\n", cached_info.Values); + ok(cached_info.MaxValueNameLen == 6, "cached_info.MaxValueNameLen = %u\n", cached_info.MaxValueNameLen); + ok(cached_info.MaxValueDataLen == 4, "cached_info.MaxValueDataLen = %u\n", cached_info.MaxValueDataLen); + ok(cached_info.NameLength == 22, "cached_info.NameLength = %u\n", cached_info.NameLength); + } + } + + status = pNtDeleteKey(subkey2); + ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); + status = pNtDeleteKey(subkey); + ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); + + pNtClose(subkey2); + pNtClose(subkey); pNtClose(key); } +static void test_notify(void) +{ + OBJECT_ATTRIBUTES attr; + LARGE_INTEGER timeout; + IO_STATUS_BLOCK iosb; + UNICODE_STRING str; + HANDLE key, events[2], subkey; + NTSTATUS status; + + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); + status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); + + events[0] = CreateEventW(NULL, FALSE, TRUE, NULL); + ok(events[0] != NULL, "CreateEvent failed: %u\n", GetLastError()); + events[1] = CreateEventW(NULL, FALSE, TRUE, NULL); + ok(events[1] != NULL, "CreateEvent failed: %u\n", GetLastError()); + + status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + + timeout.QuadPart = 0; + status = pNtWaitForSingleObject(events[0], FALSE, &timeout); + ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status); + status = pNtWaitForSingleObject(events[1], FALSE, &timeout); + ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status); + + attr.RootDirectory = key; + attr.ObjectName = &str; + + pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); + status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); + + status = pNtWaitForSingleObject(events[0], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + status = pNtWaitForSingleObject(events[1], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + + status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + + status = pNtDeleteKey(subkey); + ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); + + status = pNtWaitForSingleObject(events[0], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + status = pNtWaitForSingleObject(events[1], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + + pNtClose(subkey); + + status = pNtNotifyChangeKey(key, events[0], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + status = pNtNotifyChangeKey(key, events[1], NULL, NULL, &iosb, 0, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + + pNtClose(key); + + status = pNtWaitForSingleObject(events[0], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + status = pNtWaitForSingleObject(events[1], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + + if (pNtNotifyChangeMultipleKeys) + { + InitializeObjectAttributes(&attr, &winetestpath, 0, 0, 0); + status = pNtOpenKey(&key, KEY_ALL_ACCESS, &attr); + ok(status == STATUS_SUCCESS, "NtOpenKey Failed: 0x%08x\n", status); + + status = pNtNotifyChangeMultipleKeys(key, 0, NULL, events[0], NULL, NULL, &iosb, REG_NOTIFY_CHANGE_NAME, FALSE, NULL, 0, TRUE); + ok(status == STATUS_PENDING, "NtNotifyChangeKey returned %x\n", status); + + timeout.QuadPart = 0; + status = pNtWaitForSingleObject(events[0], FALSE, &timeout); + ok(status == STATUS_TIMEOUT, "NtWaitForSingleObject returned %x\n", status); + + attr.RootDirectory = key; + attr.ObjectName = &str; + pRtlCreateUnicodeStringFromAsciiz(&str, "test_subkey"); + status = pNtCreateKey(&subkey, GENERIC_ALL, &attr, 0, 0, 0, 0); + ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status); + + status = pNtWaitForSingleObject(events[0], FALSE, &timeout); + ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status); + + status = pNtDeleteKey(subkey); + ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status); + pNtClose(subkey); + pNtClose(key); + } + else + { + win_skip("NtNotifyChangeMultipleKeys not available\n"); + } + + pNtClose(events[0]); + pNtClose(events[1]); +} + START_TEST(reg) { static const WCHAR winetest[] = {'\\','W','i','n','e','T','e','s','t',0}; @@ -1512,6 +1707,7 @@ START_TEST(reg) test_NtQueryLicenseKey(); test_NtQueryValueKey(); test_long_value_name(); + test_notify(); test_NtDeleteKey(); test_symlinks(); test_redirection(); diff --git a/rostests/winetests/ntdll/rtl.c b/rostests/winetests/ntdll/rtl.c index bf2c22e0128..90b93235ce0 100755 --- a/rostests/winetests/ntdll/rtl.c +++ b/rostests/winetests/ntdll/rtl.c @@ -108,6 +108,8 @@ static NTSTATUS (WINAPI *pRtlGetCompressionWorkSpaceSize)(USHORT, PULONG, PULON 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 BOOL (WINAPI *pRtlIsCriticalSectionLocked)(RTL_CRITICAL_SECTION *); +static BOOL (WINAPI *pRtlIsCriticalSectionLockedByThread)(RTL_CRITICAL_SECTION *); static HMODULE hkernel32 = 0; static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); @@ -170,6 +172,8 @@ static void InitFunctionPtrs(void) pRtlDecompressBuffer = (void *)GetProcAddress(hntdll, "RtlDecompressBuffer"); pRtlDecompressFragment = (void *)GetProcAddress(hntdll, "RtlDecompressFragment"); pRtlCompressBuffer = (void *)GetProcAddress(hntdll, "RtlCompressBuffer"); + pRtlIsCriticalSectionLocked = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLocked"); + pRtlIsCriticalSectionLockedByThread = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLockedByThread"); } hkernel32 = LoadLibraryA("kernel32.dll"); ok(hkernel32 != 0, "LoadLibrary failed\n"); @@ -722,46 +726,11 @@ static void test_RtlUniform(void) } -static ULONG my_RtlRandom(PULONG seed) -{ - static ULONG saved_value[128] = - { /* 0 */ 0x4c8bc0aa, 0x4c022957, 0x2232827a, 0x2f1e7626, 0x7f8bdafb, 0x5c37d02a, 0x0ab48f72, 0x2f0c4ffa, - /* 8 */ 0x290e1954, 0x6b635f23, 0x5d3885c0, 0x74b49ff8, 0x5155fa54, 0x6214ad3f, 0x111e9c29, 0x242a3a09, - /* 16 */ 0x75932ae1, 0x40ac432e, 0x54f7ba7a, 0x585ccbd5, 0x6df5c727, 0x0374dad1, 0x7112b3f1, 0x735fc311, - /* 24 */ 0x404331a9, 0x74d97781, 0x64495118, 0x323e04be, 0x5974b425, 0x4862e393, 0x62389c1d, 0x28a68b82, - /* 32 */ 0x0f95da37, 0x7a50bbc6, 0x09b0091c, 0x22cdb7b4, 0x4faaed26, 0x66417ccd, 0x189e4bfa, 0x1ce4e8dd, - /* 40 */ 0x5274c742, 0x3bdcf4dc, 0x2d94e907, 0x32eac016, 0x26d33ca3, 0x60415a8a, 0x31f57880, 0x68c8aa52, - /* 48 */ 0x23eb16da, 0x6204f4a1, 0x373927c1, 0x0d24eb7c, 0x06dd7379, 0x2b3be507, 0x0f9c55b1, 0x2c7925eb, - /* 56 */ 0x36d67c9a, 0x42f831d9, 0x5e3961cb, 0x65d637a8, 0x24bb3820, 0x4d08e33d, 0x2188754f, 0x147e409e, - /* 64 */ 0x6a9620a0, 0x62e26657, 0x7bd8ce81, 0x11da0abb, 0x5f9e7b50, 0x23e444b6, 0x25920c78, 0x5fc894f0, - /* 72 */ 0x5e338cbb, 0x404237fd, 0x1d60f80f, 0x320a1743, 0x76013d2b, 0x070294ee, 0x695e243b, 0x56b177fd, - /* 80 */ 0x752492e1, 0x6decd52f, 0x125f5219, 0x139d2e78, 0x1898d11e, 0x2f7ee785, 0x4db405d8, 0x1a028a35, - /* 88 */ 0x63f6f323, 0x1f6d0078, 0x307cfd67, 0x3f32a78a, 0x6980796c, 0x462b3d83, 0x34b639f2, 0x53fce379, - /* 96 */ 0x74ba50f4, 0x1abc2c4b, 0x5eeaeb8d, 0x335a7a0d, 0x3973dd20, 0x0462d66b, 0x159813ff, 0x1e4643fd, - /* 104 */ 0x06bc5c62, 0x3115e3fc, 0x09101613, 0x47af2515, 0x4f11ec54, 0x78b99911, 0x3db8dd44, 0x1ec10b9b, - /* 112 */ 0x5b5506ca, 0x773ce092, 0x567be81a, 0x5475b975, 0x7a2cde1a, 0x494536f5, 0x34737bb4, 0x76d9750b, - /* 120 */ 0x2a1f6232, 0x2e49644d, 0x7dddcbe7, 0x500cebdb, 0x619dab9e, 0x48c626fe, 0x1cda3193, 0x52dabe9d }; - ULONG rand; - int pos; - ULONG result; - - rand = (*seed * 0x7fffffed + 0x7fffffc3) % 0x7fffffff; - *seed = (rand * 0x7fffffed + 0x7fffffc3) % 0x7fffffff; - pos = *seed & 0x7f; - result = saved_value[pos]; - saved_value[pos] = rand; - return(result); -} - - static void test_RtlRandom(void) { - ULONGLONG num; + int i, j; ULONG seed; - ULONG seed_bak; - ULONG seed_expected; - ULONG result; - ULONG result_expected; + ULONG res[512]; if (!pRtlRandom) { @@ -769,185 +738,14 @@ static void test_RtlRandom(void) return; } -/* - * Unlike RtlUniform, RtlRandom is not documented. We guess that for - * RtlRandom D.H. Lehmer's 1948 algorithm is used like stated in - * the documentation of the RtlUniform function. This algorithm is: - * - * seed = (seed * const_1 + const_2) % const_3; - * - * According to the RtlUniform documentation the random number is - * distributed over [0..MAXLONG], but in reality it is distributed - * over [0..MAXLONG-1]. Therefore const_3 might be MAXLONG + 1 or - * MAXLONG: - * - * seed = (seed * const_1 + const_2) % (MAXLONG + 1); - * - * or - * - * seed = (seed * const_1 + const_2) % MAXLONG; - * - * To find out const_2 we just call RtlRandom with seed set to 0: - */ seed = 0; - result_expected = 0x320a1743; - seed_expected =0x44b; - result = pRtlRandom(&seed); - -/* - * Windows Vista uses different algorithms, so skip the rest of the tests - * until that is figured out. Trace output for the failures is about 10.5 MB! - */ - - if (seed == 0x3fc) { - skip("Most likely running on Windows Vista which uses a different algorithm\n"); - return; + for (i = 0; i < sizeof(res) / sizeof(res[0]); i++) + { + res[i] = pRtlRandom(&seed); + ok(seed != res[i], "%i: seed is same as res %x\n", i, seed); + for (j = 0; j < i; j++) + ok(res[i] != res[j], "res[%i] (%x) is same as res[%i] (%x)\n", j, res[j], i, res[i]); } - - ok(result == result_expected, - "pRtlRandom(&seed (seed == 0)) returns %x, expected %x\n", - result, result_expected); - ok(seed == seed_expected, - "pRtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n", - seed, seed_expected); -/* - * Seed is not equal to result as with RtlUniform. To see more we - * call RtlRandom again with seed set to 0: - */ - seed = 0; - result_expected = 0x7fffffc3; - seed_expected =0x44b; - result = pRtlRandom(&seed); - ok(result == result_expected, - "RtlRandom(&seed (seed == 0)) returns %x, expected %x\n", - result, result_expected); - ok(seed == seed_expected, - "RtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n", - seed, seed_expected); -/* - * Seed is set to the same value as before but the result is different. - * To see more we call RtlRandom again with seed set to 0: - */ - seed = 0; - result_expected = 0x7fffffc3; - seed_expected =0x44b; - result = pRtlRandom(&seed); - ok(result == result_expected, - "RtlRandom(&seed (seed == 0)) returns %x, expected %x\n", - result, result_expected); - ok(seed == seed_expected, - "RtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n", - seed, seed_expected); -/* - * Seed is again set to the same value as before. This time we also - * have the same result as before. Interestingly the value of the - * result is 0x7fffffc3 which is the same value used in RtlUniform - * as const_2. If we do - * - * seed = 0; - * result = RtlUniform(&seed); - * - * we get the same result (0x7fffffc3) as with - * - * seed = 0; - * RtlRandom(&seed); - * seed = 0; - * result = RtlRandom(&seed); - * - * And there is another interesting thing. If we do - * - * seed = 0; - * RtlUniform(&seed); - * RtlUniform(&seed); - * - * seed is set to the value 0x44b which ist the same value that - * - * seed = 0; - * RtlRandom(&seed); - * - * assigns to seed. Putting these two findings together leads to - * the conclusion that RtlRandom saves the value in some variable, - * like in the following algorithm: - * - * result = saved_value; - * saved_value = RtlUniform(&seed); - * RtlUniform(&seed); - * return(result); - * - * Now we do further tests with seed set to 1: - */ - seed = 1; - result_expected = 0x7a50bbc6; - seed_expected =0x5a1; - result = pRtlRandom(&seed); - ok(result == result_expected, - "RtlRandom(&seed (seed == 1)) returns %x, expected %x\n", - result, result_expected); - ok(seed == seed_expected, - "RtlRandom(&seed (seed == 1)) sets seed to %x, expected %x\n", - seed, seed_expected); -/* - * If there is just one saved_value the result now would be - * 0x7fffffc3. From this test we can see that there is more than - * one saved_value, like with this algorithm: - * - * result = saved_value[pos]; - * saved_value[pos] = RtlUniform(&seed); - * RtlUniform(&seed); - * return(result); - * - * But how is the value of pos determined? The calls to RtlUniform - * create a sequence of random numbers. Every second random number - * is put into the saved_value array and is used in some later call - * of RtlRandom as result. The only reasonable source to determine - * pos are the random numbers generated by RtlUniform which are not - * put into the saved_value array. This are the values of seed - * between the two calls of RtlUniform as in this algorithm: - * - * rand = RtlUniform(&seed); - * RtlUniform(&seed); - * pos = position(seed); - * result = saved_value[pos]; - * saved_value[pos] = rand; - * return(result); - * - * What remains to be determined is: The size of the saved_value array, - * the initial values of the saved_value array and the function - * position(seed). These tests are not shown here. - * The result of these tests is: The size of the saved_value array - * is 128, the initial values can be seen in the my_RtlRandom - * function and the position(seed) function is (seed & 0x7f). - * - * For a full test of RtlRandom use one of the following loop heads: - * - * for (num = 0; num <= 0xffffffff; num++) { - * seed = num; - * ... - * - * seed = 0; - * for (num = 0; num <= 0xffffffff; num++) { - * ... - */ - seed = 0; - for (num = 0; num <= 100000; num++) { - seed_bak = seed; - seed_expected = seed; - result_expected = my_RtlRandom(&seed_expected); - /* The following corrections are necessary because the */ - /* previous tests changed the saved_value array */ - if (num == 0) { - result_expected = 0x7fffffc3; - } else if (num == 81) { - result_expected = 0x7fffffb1; - } /* if */ - result = pRtlRandom(&seed); - ok(result == result_expected, - "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n", - (DWORD)(num >> 32), (DWORD)num, seed_bak, result, result_expected); - ok(seed == seed_expected, - "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n", - (DWORD)(num >> 32), (DWORD)num, seed_bak, result, seed_expected); - } /* for */ } @@ -2716,6 +2514,79 @@ static void test_LdrLockLoaderLock(void) pLdrUnlockLoaderLock(0, magic); } +static void test_RtlCompressBuffer(void) +{ + ULONG compress_workspace, decompress_workspace; + static const UCHAR test_buffer[] = "WineWineWine"; + static UCHAR buf1[0x1000], buf2[0x1000]; + ULONG final_size, buf_size; + UCHAR *workspace = NULL; + NTSTATUS status; + + if (!pRtlCompressBuffer || !pRtlDecompressBuffer || !pRtlGetCompressionWorkSpaceSize) + { + win_skip("skipping RtlCompressBuffer tests, required functions 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 %u\n", compress_workspace); + workspace = HeapAlloc(GetProcessHeap(), 0, compress_workspace); + ok(workspace != NULL, "HeapAlloc failed %d\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 %u\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 %u\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 %u\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); + todo_wine + ok(final_size < sizeof(test_buffer), "got wrong final_size %u\n", final_size); + + /* test decompression */ + buf_size = final_size; + 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 %u\n", final_size); + ok(!memcmp(buf2, test_buffer, sizeof(test_buffer)), "got wrong decoded data\n"); + ok(buf2[sizeof(test_buffer)] == 0x11, "too many bytes written\n"); + + /* 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); +} + static void test_RtlGetCompressionWorkSpaceSize(void) { ULONG compress_workspace, decompress_workspace; @@ -2727,6 +2598,7 @@ static void test_RtlGetCompressionWorkSpaceSize(void) return; } + /* test invalid format / engine */ status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_NONE, &compress_workspace, &decompress_workspace); ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status); @@ -2738,27 +2610,30 @@ static void test_RtlGetCompressionWorkSpaceSize(void) status = pRtlGetCompressionWorkSpaceSize(0xFF, &compress_workspace, &decompress_workspace); ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status); + /* test LZNT1 with normal and maximum compression */ 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); + ok(compress_workspace != 0, "got wrong compress_workspace %u\n", compress_workspace); + ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %u\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); + ok(compress_workspace != 0, "got wrong compress_workspace %u\n", compress_workspace); + ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %u\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; @@ -2769,16 +2644,15 @@ static BOOL is_incomplete_chunk(const UCHAR *compressed, ULONG compressed_size, compressed += sizeof(WORD) + chunk_size; compressed_size -= sizeof(WORD) + chunk_size; } + return FALSE; } -#define DECOMPRESS_BROKEN_TRUNCATED 1 -#define DECOMPRESS_BROKEN_FRAGMENT 2 +#define DECOMPRESS_BROKEN_FRAGMENT 1 /* < Win 7 */ +#define DECOMPRESS_BROKEN_TRUNCATED 2 /* broken on all machines */ 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]; @@ -2994,28 +2868,28 @@ static void test_RtlDecompressBuffer(void) /* test compression format / engine */ final_size = 0xdeadbeef; - status = pRtlDecompressBuffer(COMPRESSION_FORMAT_NONE, buf, sizeof(buf) - 1, test_lznt[0].compressed, + status = pRtlDecompressBuffer(COMPRESSION_FORMAT_NONE, buf, sizeof(buf), 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); + ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size); final_size = 0xdeadbeef; - status = pRtlDecompressBuffer(COMPRESSION_FORMAT_DEFAULT, buf, sizeof(buf) - 1, test_lznt[0].compressed, + status = pRtlDecompressBuffer(COMPRESSION_FORMAT_DEFAULT, buf, sizeof(buf), 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); + ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size); final_size = 0xdeadbeef; - status = pRtlDecompressBuffer(0xFF, buf, sizeof(buf) - 1, test_lznt[0].compressed, + status = pRtlDecompressBuffer(0xFF, buf, sizeof(buf), 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); + ok(final_size == 0xdeadbeef, "got wrong final_size %u\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); + trace("Running test %d (compressed_size=%u, uncompressed_size=%u, status=0x%08x)\n", + i, test_lznt[i].compressed_size, test_lznt[i].uncompressed_size, test_lznt[i].status); /* test with very big buffer */ final_size = 0xdeadbeef; @@ -3027,11 +2901,11 @@ static void test_RtlDecompressBuffer(void) if (!status) { ok(final_size == test_lznt[i].uncompressed_size, - "%d: got wrong final_size %d\n", i, final_size); + "%d: got wrong final_size %u\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); + "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size); } /* test that modifier for compression engine is ignored */ @@ -3044,11 +2918,11 @@ static void test_RtlDecompressBuffer(void) if (!status) { ok(final_size == test_lznt[i].uncompressed_size, - "%d: got wrong final_size %d\n", i, final_size); + "%d: got wrong final_size %u\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); + "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size); } /* test with expected output size */ @@ -3062,11 +2936,11 @@ static void test_RtlDecompressBuffer(void) if (!status) { ok(final_size == test_lznt[i].uncompressed_size, - "%d: got wrong final_size %d\n", i, final_size); + "%d: got wrong final_size %u\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); + "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size); } } @@ -3077,16 +2951,19 @@ static void test_RtlDecompressBuffer(void) 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 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_TRUNCATED) + todo_wine + ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status); + else + 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 - 1, - "%d: got wrong final_size %d\n", i, final_size); + "%d: got wrong final_size %u\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); + "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size - 1); } } @@ -3096,82 +2973,84 @@ static void test_RtlDecompressBuffer(void) 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); + ok(final_size == 0, "%d: got wrong final_size %u\n", i, final_size); + ok(buf[0] == 0x11, "%d: buf[0] was modified\n", i); } - /* test RtlDecompressBuffer with offset = 0 */ + /* test RtlDecompressFragment 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_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status); + if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT) + todo_wine + ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status); + else + 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); + "%d: got wrong final_size %u\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); + "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size); } - /* test RtlDecompressBuffer with offset = 1 */ + /* test RtlDecompressFragment 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_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status); + if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT) + todo_wine + ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status); + else + ok(status == test_lznt[i].status, "%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); + ok(final_size == 4095, "%d: got wrong final_size %u\n", i, final_size); /* Buffer doesn't contain any useful value on Windows */ - ok(buf[4095] == 0x11, - "%d: buf[4095] overwritten\n", i); + ok(buf[4095] == 0x11, "%d: buf[4095] was modified\n", i); } else { ok(final_size == test_lznt[i].uncompressed_size - 1, - "%d: got wrong final_size %d\n", i, final_size); + "%d: got wrong final_size %u\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); + "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size - 1); } } - /* test RtlDecompressBuffer with offset = 4095 */ + /* test RtlDecompressFragment 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_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status); + if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT) + todo_wine + ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status); + else + ok(status == test_lznt[i].status, "%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); + ok(final_size == 1, "%d: got wrong final_size %u\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); + ok(buf[0] == 0, "%d: padding is not zero\n", i); + ok(buf[1] == 0x11, "%d: buf[1] was modified\n", i); } - /* test RtlDecompressBuffer with offset = 4096 */ + /* test RtlDecompressFragment with offset = 4096 */ final_size = 0xdeadbeef; memset(buf, 0x11, sizeof(buf)); status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed, @@ -3181,263 +3060,109 @@ static void test_RtlDecompressBuffer(void) 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); + ok(final_size == 0, "%d: got wrong final_size %u\n", i, final_size); + ok(buf[0] == 0x11, "%d: buf[4096] was modified\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 || broken(status == STATUS_BAD_COMPRESSION_BUFFER), - "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 || broken(status == STATUS_BAD_COMPRESSION_BUFFER), - "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 || 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"); - } - - 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; +#undef DECOMPRESS_BROKEN_FRAGMENT +#undef DECOMPRESS_BROKEN_TRUNCATED - if (!pRtlCompressBuffer || !pRtlGetCompressionWorkSpaceSize) +struct critsect_locked_info +{ + CRITICAL_SECTION crit; + HANDLE semaphores[2]; +}; + +static DWORD WINAPI critsect_locked_thread(void *param) +{ + struct critsect_locked_info *info = param; + DWORD ret; + + ret = pRtlIsCriticalSectionLocked(&info->crit); + ok(ret == TRUE, "expected TRUE, got %u\n", ret); + ret = pRtlIsCriticalSectionLockedByThread(&info->crit); + ok(ret == FALSE, "expected FALSE, got %u\n", ret); + + ReleaseSemaphore(info->semaphores[0], 1, NULL); + ret = WaitForSingleObject(info->semaphores[1], 1000); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret); + + ret = pRtlIsCriticalSectionLocked(&info->crit); + ok(ret == FALSE, "expected FALSE, got %u\n", ret); + ret = pRtlIsCriticalSectionLockedByThread(&info->crit); + ok(ret == FALSE, "expected FALSE, got %u\n", ret); + + EnterCriticalSection(&info->crit); + + ret = pRtlIsCriticalSectionLocked(&info->crit); + ok(ret == TRUE, "expected TRUE, got %u\n", ret); + ret = pRtlIsCriticalSectionLockedByThread(&info->crit); + ok(ret == TRUE, "expected TRUE, got %u\n", ret); + + ReleaseSemaphore(info->semaphores[0], 1, NULL); + ret = WaitForSingleObject(info->semaphores[1], 1000); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret); + + LeaveCriticalSection(&info->crit); + return 0; +} + +static void test_RtlIsCriticalSectionLocked(void) +{ + struct critsect_locked_info info; + HANDLE thread; + BOOL ret; + + if (!pRtlIsCriticalSectionLocked || !pRtlIsCriticalSectionLockedByThread) { - win_skip("RtlCompressBuffer or RtlGetCompressionWorkSpaceSize is not available\n"); + win_skip("skipping RtlIsCriticalSectionLocked tests, required functions 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); + InitializeCriticalSection(&info.crit); + info.semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL); + ok(info.semaphores[0] != NULL, "CreateSemaphore failed with %u\n", GetLastError()); + info.semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL); + ok(info.semaphores[1] != NULL, "CreateSemaphore failed with %u\n", GetLastError()); - workspace = HeapAlloc( GetProcessHeap(), 0, compress_workspace ); - ok(workspace != NULL, "HeapAlloc failed %x\n", GetLastError()); + ret = pRtlIsCriticalSectionLocked(&info.crit); + ok(ret == FALSE, "expected FALSE, got %u\n", ret); + ret = pRtlIsCriticalSectionLockedByThread(&info.crit); + ok(ret == FALSE, "expected FALSE, got %u\n", ret); - /* 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); + EnterCriticalSection(&info.crit); - 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); + ret = pRtlIsCriticalSectionLocked(&info.crit); + ok(ret == TRUE, "expected TRUE, got %u\n", ret); + ret = pRtlIsCriticalSectionLockedByThread(&info.crit); + ok(ret == TRUE, "expected TRUE, got %u\n", ret); - 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); + thread = CreateThread(NULL, 0, critsect_locked_thread, &info, 0, NULL); + ok(thread != NULL, "CreateThread failed with %u\n", GetLastError()); + ret = WaitForSingleObject(info.semaphores[0], 1000); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret); - /* 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); + LeaveCriticalSection(&info.crit); - /* 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)); + ReleaseSemaphore(info.semaphores[1], 1, NULL); + ret = WaitForSingleObject(info.semaphores[0], 1000); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret); - /* 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); + ret = pRtlIsCriticalSectionLocked(&info.crit); + ok(ret == TRUE, "expected TRUE, got %u\n", ret); + ret = pRtlIsCriticalSectionLockedByThread(&info.crit); + ok(ret == FALSE, "expected FALSE, got %u\n", ret); - HeapFree(GetProcessHeap(), 0, workspace); + ReleaseSemaphore(info.semaphores[1], 1, NULL); + ret = WaitForSingleObject(thread, 1000); + ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret); + + CloseHandle(thread); + CloseHandle(info.semaphores[0]); + CloseHandle(info.semaphores[1]); + DeleteCriticalSection(&info.crit); } START_TEST(rtl) @@ -3477,7 +3202,8 @@ START_TEST(rtl) test_RtlIpv6StringToAddressEx(); test_LdrAddRefDll(); test_LdrLockLoaderLock(); + test_RtlCompressBuffer(); test_RtlGetCompressionWorkSpaceSize(); test_RtlDecompressBuffer(); - test_RtlCompressBuffer(); + test_RtlIsCriticalSectionLocked(); }