From d0b5fb1fa826ede3c1b9270465601bcf981fb10b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 13 Dec 2019 21:43:41 -0600 Subject: [PATCH] kernelbase: Implement ReOpenFile(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47668 Signed-off-by: Zebediah Figura --- dlls/kernel32/tests/file.c | 103 +++++++++++++++++++++++++++++++++++++ dlls/kernelbase/file.c | 99 ++++++++++++++++++++++++++--------- 2 files changed, 179 insertions(+), 23 deletions(-) diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 5bd168276f9..7dd138c7eb7 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -59,6 +59,7 @@ static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(LPCWSTR, PUNICODE_STRING, PW static NTSTATUS (WINAPI *pRtlAnsiStringToUnicodeString)(PUNICODE_STRING, PCANSI_STRING, BOOLEAN); static BOOL (WINAPI *pSetFileInformationByHandle)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, void*, DWORD); static BOOL (WINAPI *pGetQueuedCompletionStatusEx)(HANDLE, OVERLAPPED_ENTRY*, ULONG, ULONG*, DWORD, BOOL); +static HANDLE (WINAPI *pReOpenFile)(HANDLE, DWORD, DWORD, DWORD); static void (WINAPI *pRtlInitAnsiString)(PANSI_STRING,PCSZ); static void (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); static BOOL (WINAPI *pSetFileCompletionNotificationModes)(HANDLE, UCHAR); @@ -111,6 +112,7 @@ static void InitFunctionPointers(void) pGetFinalPathNameByHandleW = (void *) GetProcAddress(hkernel32, "GetFinalPathNameByHandleW"); pSetFileInformationByHandle = (void *) GetProcAddress(hkernel32, "SetFileInformationByHandle"); pGetQueuedCompletionStatusEx = (void *) GetProcAddress(hkernel32, "GetQueuedCompletionStatusEx"); + pReOpenFile = (void *) GetProcAddress(hkernel32, "ReOpenFile"); pSetFileCompletionNotificationModes = (void *)GetProcAddress(hkernel32, "SetFileCompletionNotificationModes"); pFindFirstStreamW = (void *)GetProcAddress(hkernel32, "FindFirstStreamW"); } @@ -4410,6 +4412,104 @@ static void test_SetFileValidData(void) DeleteFileA(filename); } +static void test_ReOpenFile(void) +{ + char path[MAX_PATH], filename[MAX_PATH], buffer[4]; + HANDLE file, new; + unsigned int i; + DWORD size; + BOOL ret; + + static const DWORD invalid_attributes[] = + { + FILE_ATTRIBUTE_ARCHIVE, + FILE_ATTRIBUTE_ENCRYPTED, + FILE_ATTRIBUTE_HIDDEN, + FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_OFFLINE, + FILE_ATTRIBUTE_READONLY, + FILE_ATTRIBUTE_SYSTEM, + FILE_ATTRIBUTE_TEMPORARY, + }; + + static const DWORD valid_attributes[] = + { + FILE_FLAG_BACKUP_SEMANTICS, + FILE_FLAG_NO_BUFFERING, + FILE_FLAG_OVERLAPPED, + FILE_FLAG_RANDOM_ACCESS, + FILE_FLAG_SEQUENTIAL_SCAN, + FILE_FLAG_WRITE_THROUGH, + }; + + if (!pReOpenFile) + { + win_skip("ReOpenFile() is not available\n"); + return; + } + + GetTempPathA(sizeof(path), path); + GetTempFileNameA(path, "tst", 0, filename); + + file = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError()); + ret = WriteFile(file, "foo", 4, &size, NULL); + ok(ret, "failed to write file, error %u\n", GetLastError()); + + for (i = 0; i < ARRAY_SIZE(invalid_attributes); ++i) + { + SetLastError(0xdeadbeef); + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, invalid_attributes[i]); + ok(new == INVALID_HANDLE_VALUE, "got %p\n", new); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError()); + } + + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + ok(new != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError()); + + ret = ReadFile(new, buffer, sizeof(buffer), &size, NULL); + ok(ret, "failed to read file, error %u\n", GetLastError()); + ok(size == 4, "got size %u\n", size); + ok(!strcmp(buffer, "foo"), "got wrong data\n"); + CloseHandle(new); + + for (i = 0; i < ARRAY_SIZE(valid_attributes); ++i) + { + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, valid_attributes[i]); + ok(new != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError()); + CloseHandle(new); + } + + SetLastError(0xdeadbeef); + new = pReOpenFile(file, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + ok(new == INVALID_HANDLE_VALUE, "got %p\n", new); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "got error %u\n", GetLastError()); + + CloseHandle(file); + ret = DeleteFileA(filename); + ok(ret, "failed to delete file, error %u\n", GetLastError()); + + file = CreateNamedPipeA("\\\\.\\pipe\\test_pipe", PIPE_ACCESS_DUPLEX, 0, 1, 1000, 1000, 1000, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed to create pipe, error %u\n", GetLastError()); + + new = pReOpenFile(file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + todo_wine ok(new != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError()); + + ret = WriteFile(file, "foo", 4, &size, NULL); + todo_wine ok(ret, "failed to write file, error %u\n", GetLastError()); + ret = ReadFile(new, buffer, sizeof(buffer), &size, NULL); + todo_wine ok(ret, "failed to read file, error %u\n", GetLastError()); + if (ret) + { + ok(size == 4, "got size %u\n", size); + ok(!strcmp(buffer, "foo"), "got wrong data\n"); + } + + CloseHandle(new); + CloseHandle(file); +} + static void test_WriteFileGather(void) { char temp_path[MAX_PATH], filename[MAX_PATH]; @@ -5424,6 +5524,8 @@ START_TEST(file) ret = DeleteFileA(filename); ok(ret != 0, "DeleteFile error %u\n", GetLastError()); + test_ReOpenFile(); return; + test__hread( ); test__hwrite( ); test__lclose( ); @@ -5483,4 +5585,5 @@ START_TEST(file) test_file_readonly_access(); test_find_file_stream(); test_SetFileTime(); + test_ReOpenFile(); } diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index eb2ef57c7d6..66f0cbfedc4 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -432,6 +432,26 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileA( LPCSTR name, DWORD access, DWORD sh return CreateFileW( nameW, access, sharing, sa, creation, attributes, template ); } +static UINT get_nt_file_options( DWORD attributes ) +{ + UINT options = 0; + + if (attributes & FILE_FLAG_BACKUP_SEMANTICS) + options |= FILE_OPEN_FOR_BACKUP_INTENT; + else + options |= FILE_NON_DIRECTORY_FILE; + if (attributes & FILE_FLAG_DELETE_ON_CLOSE) + options |= FILE_DELETE_ON_CLOSE; + if (attributes & FILE_FLAG_NO_BUFFERING) + options |= FILE_NO_INTERMEDIATE_BUFFERING; + if (!(attributes & FILE_FLAG_OVERLAPPED)) + options |= FILE_SYNCHRONOUS_IO_NONALERT; + if (attributes & FILE_FLAG_RANDOM_ACCESS) + options |= FILE_RANDOM_ACCESS; + if (attributes & FILE_FLAG_WRITE_THROUGH) + options |= FILE_WRITE_THROUGH; + return options; +} /************************************************************************* * CreateFileW (kernelbase.@) @@ -441,7 +461,6 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO DWORD attributes, HANDLE template ) { NTSTATUS status; - UINT options; OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; IO_STATUS_BLOCK io; @@ -543,25 +562,8 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO /* now call NtCreateFile */ - options = 0; - if (attributes & FILE_FLAG_BACKUP_SEMANTICS) - options |= FILE_OPEN_FOR_BACKUP_INTENT; - else - options |= FILE_NON_DIRECTORY_FILE; if (attributes & FILE_FLAG_DELETE_ON_CLOSE) - { - options |= FILE_DELETE_ON_CLOSE; access |= DELETE; - } - if (attributes & FILE_FLAG_NO_BUFFERING) - options |= FILE_NO_INTERMEDIATE_BUFFERING; - if (!(attributes & FILE_FLAG_OVERLAPPED)) - options |= FILE_SYNCHRONOUS_IO_NONALERT; - if (attributes & FILE_FLAG_RANDOM_ACCESS) - options |= FILE_RANDOM_ACCESS; - if (attributes & FILE_FLAG_WRITE_THROUGH) - options |= FILE_WRITE_THROUGH; - attributes &= FILE_ATTRIBUTE_VALID_FLAGS; attr.Length = sizeof(attr); attr.RootDirectory = 0; @@ -582,8 +584,9 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO if (sa && sa->bInheritHandle) attr.Attributes |= OBJ_INHERIT; status = NtCreateFile( &ret, access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &io, - NULL, attributes, sharing, nt_disposition[creation - CREATE_NEW], - options, NULL, 0 ); + NULL, attributes & FILE_ATTRIBUTE_VALID_FLAGS, sharing, + nt_disposition[creation - CREATE_NEW], + get_nt_file_options( attributes ), NULL, 0 ); if (status) { if (vxd_name && vxd_name[0]) @@ -2550,10 +2553,60 @@ HANDLE WINAPI DECLSPEC_HOTPATCH OpenFileById( HANDLE handle, LPFILE_ID_DESCRIPTO /*********************************************************************** * ReOpenFile (kernelbase.@) */ -HANDLE WINAPI /* DECLSPEC_HOTPATCH */ ReOpenFile( HANDLE handle, DWORD access, DWORD sharing, DWORD flags ) +HANDLE WINAPI DECLSPEC_HOTPATCH ReOpenFile( HANDLE handle, DWORD access, DWORD sharing, DWORD attributes ) { - FIXME( "(%p, %d, %d, %d): stub\n", handle, access, sharing, flags ); - return INVALID_HANDLE_VALUE; + SECURITY_QUALITY_OF_SERVICE qos; + OBJECT_NAME_INFORMATION *name; + OBJECT_ATTRIBUTES attr = {}; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE file; + DWORD size; + + TRACE("handle %p, access %#x, sharing %#x, attributes %#x.\n", handle, access, sharing, attributes); + + if (attributes & 0x7ffff) /* FILE_ATTRIBUTE_* flags are invalid */ + { + SetLastError(ERROR_INVALID_PARAMETER); + return INVALID_HANDLE_VALUE; + } + + status = NtQueryObject( handle, ObjectNameInformation, NULL, 0, &size ); + if (status != STATUS_INFO_LENGTH_MISMATCH && !set_ntstatus( status )) + return INVALID_HANDLE_VALUE; + + if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, size ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return INVALID_HANDLE_VALUE; + } + + status = NtQueryObject( handle, ObjectNameInformation, name, size, NULL ); + if (!set_ntstatus( status )) + return INVALID_HANDLE_VALUE; + + if (attributes & FILE_FLAG_DELETE_ON_CLOSE) + access |= DELETE; + + attr.Length = sizeof(attr); + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &name->Name; + if (attributes & SECURITY_SQOS_PRESENT) + { + qos.Length = sizeof(qos); + qos.ImpersonationLevel = (attributes >> 16) & 0x3; + qos.ContextTrackingMode = attributes & SECURITY_CONTEXT_TRACKING ? SECURITY_DYNAMIC_TRACKING : SECURITY_STATIC_TRACKING; + qos.EffectiveOnly = (attributes & SECURITY_EFFECTIVE_ONLY) != 0; + attr.SecurityQualityOfService = &qos; + } + else + attr.SecurityQualityOfService = NULL; + + status = NtCreateFile( &file, access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &io, NULL, + 0, sharing, FILE_OPEN, get_nt_file_options( attributes ), NULL, 0 ); + if (!set_ntstatus( status )) + return INVALID_HANDLE_VALUE; + return file; } -- 2.24.0