This repository has been archived by the owner on Oct 1, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added patch to implement support for SetFileCompletionNotificationModes.
- Loading branch information
Showing
6 changed files
with
338 additions
and
41 deletions.
There are no files selected for viewing
26 changes: 0 additions & 26 deletions
26
...mpletionNotificationModes/0001-kernel32-Fake-success-in-SetFileCompletionNotificati.patch
This file was deleted.
Oops, something went wrong.
312 changes: 312 additions & 0 deletions
312
...mpletionNotificationModes/0001-ntdll-Implement-FileIoCompletionNotificationInformat.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,312 @@ | ||
From 542040171f936b56bc90f663cf6118a5998179af Mon Sep 17 00:00:00 2001 | ||
From: Sebastian Lackner <sebastian@fds-team.de> | ||
Date: Sat, 15 Oct 2016 19:50:46 +0200 | ||
Subject: ntdll: Implement FileIoCompletionNotificationInformation info class. | ||
|
||
FIXME: The tests do not seem to work on all testbots yet. | ||
FIXME: Could we use the existing wineserver call instead? | ||
--- | ||
dlls/kernel32/file.c | 13 +++-- | ||
dlls/ntdll/file.c | 17 +++++++ | ||
dlls/ntdll/tests/file.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ | ||
include/winternl.h | 8 +++ | ||
server/fd.c | 21 +++++++- | ||
server/protocol.def | 8 +++ | ||
6 files changed, 193 insertions(+), 4 deletions(-) | ||
|
||
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c | ||
index cc7ead1..5fe2268 100644 | ||
--- a/dlls/kernel32/file.c | ||
+++ b/dlls/kernel32/file.c | ||
@@ -1061,13 +1061,20 @@ BOOL WINAPI SetEndOfFile( HANDLE hFile ) | ||
return FALSE; | ||
} | ||
|
||
+ | ||
/************************************************************************** | ||
* SetFileCompletionNotificationModes (KERNEL32.@) | ||
*/ | ||
-BOOL WINAPI SetFileCompletionNotificationModes( HANDLE handle, UCHAR flags ) | ||
+BOOL WINAPI SetFileCompletionNotificationModes( HANDLE file, UCHAR flags ) | ||
{ | ||
- FIXME("%p %x - stub\n", handle, flags); | ||
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | ||
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; | ||
+ IO_STATUS_BLOCK io; | ||
+ NTSTATUS status; | ||
+ | ||
+ info.Flags = flags; | ||
+ status = NtSetInformationFile( file, &io, &info, sizeof(info), FileIoCompletionNotificationInformation ); | ||
+ if (status == STATUS_SUCCESS) return TRUE; | ||
+ SetLastError( RtlNtStatusToDosError(status) ); | ||
return FALSE; | ||
} | ||
|
||
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c | ||
index 7fbde50..14715b1 100644 | ||
--- a/dlls/ntdll/file.c | ||
+++ b/dlls/ntdll/file.c | ||
@@ -2788,6 +2788,23 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io, | ||
io->u.Status = STATUS_INVALID_PARAMETER_3; | ||
break; | ||
|
||
+ case FileIoCompletionNotificationInformation: | ||
+ if (len >= sizeof(FILE_IO_COMPLETION_NOTIFICATION_INFORMATION)) | ||
+ { | ||
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *info = ptr; | ||
+ | ||
+ SERVER_START_REQ( set_fd_compl_info ) | ||
+ { | ||
+ req->handle = wine_server_obj_handle( handle ); | ||
+ req->flags = (info->Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) ? | ||
+ COMPLETION_SKIP_ON_SUCCESS : 0; | ||
+ io->u.Status = wine_server_call( req ); | ||
+ } | ||
+ SERVER_END_REQ; | ||
+ } else | ||
+ io->u.Status = STATUS_INFO_LENGTH_MISMATCH; | ||
+ break; | ||
+ | ||
case FileAllInformation: | ||
io->u.Status = STATUS_INVALID_INFO_CLASS; | ||
break; | ||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c | ||
index 586b2c9..dfaf4a5 100644 | ||
--- a/dlls/ntdll/tests/file.c | ||
+++ b/dlls/ntdll/tests/file.c | ||
@@ -3261,6 +3261,135 @@ static void test_file_all_name_information(void) | ||
HeapFree( GetProcessHeap(), 0, file_name ); | ||
} | ||
|
||
+static void test_file_completion_information(void) | ||
+{ | ||
+ static const char buf[] = "testdata"; | ||
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; | ||
+ OVERLAPPED ov, *pov; | ||
+ IO_STATUS_BLOCK io; | ||
+ NTSTATUS status; | ||
+ DWORD num_bytes; | ||
+ HANDLE port, h; | ||
+ ULONG_PTR key; | ||
+ BOOL ret; | ||
+ int i; | ||
+ | ||
+ if (!(h = create_temp_file(0))) return; | ||
+ | ||
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info) - 1, FileIoCompletionNotificationInformation); | ||
+ ok(status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_INFO_CLASS /* XP */, | ||
+ "expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); | ||
+ if (status == STATUS_INVALID_INFO_CLASS) | ||
+ { | ||
+ CloseHandle(h); | ||
+ return; | ||
+ } | ||
+ | ||
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; | ||
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); | ||
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %08x\n", status); | ||
+ | ||
+ CloseHandle(h); | ||
+ if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return; | ||
+ | ||
+ info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE; | ||
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); | ||
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); | ||
+ | ||
+ info.Flags = FILE_SKIP_SET_USER_EVENT_ON_FAST_IO; | ||
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); | ||
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); | ||
+ | ||
+ CloseHandle(h); | ||
+ if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return; | ||
+ | ||
+ memset(&ov, 0, sizeof(ov)); | ||
+ ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); | ||
+ port = CreateIoCompletionPort(h, NULL, 0xdeadbeef, 0); | ||
+ ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError()); | ||
+ | ||
+ for (i = 0; i < 10; i++) | ||
+ { | ||
+ SetLastError(0xdeadbeef); | ||
+ ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov); | ||
+ if (ret || GetLastError() != ERROR_IO_PENDING) break; | ||
+ ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE); | ||
+ ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError()); | ||
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); | ||
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError()); | ||
+ ret = FALSE; | ||
+ } | ||
+ if (ret) | ||
+ { | ||
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); | ||
+ | ||
+ key = 0; | ||
+ pov = NULL; | ||
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); | ||
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError()); | ||
+ ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key); | ||
+ ok(pov == &ov, "expected %p, got %p\n", &ov, pov); | ||
+ } | ||
+ else | ||
+ win_skip("WriteFile never returned TRUE\n"); | ||
+ | ||
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; | ||
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); | ||
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); | ||
+ | ||
+ for (i = 0; i < 10; i++) | ||
+ { | ||
+ SetLastError(0xdeadbeef); | ||
+ ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov); | ||
+ if (ret || GetLastError() != ERROR_IO_PENDING) break; | ||
+ ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE); | ||
+ ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError()); | ||
+ ret = FALSE; | ||
+ } | ||
+ if (ret) | ||
+ { | ||
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); | ||
+ | ||
+ pov = (void *)0xdeadbeef; | ||
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 500); | ||
+ ok(!ret, "GetQueuedCompletionStatus succeeded\n"); | ||
+ ok(pov == NULL, "expected NULL, got %p\n", pov); | ||
+ } | ||
+ else | ||
+ win_skip("WriteFile never returned TRUE\n"); | ||
+ | ||
+ info.Flags = 0; | ||
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation); | ||
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status); | ||
+ | ||
+ for (i = 0; i < 10; i++) | ||
+ { | ||
+ SetLastError(0xdeadbeef); | ||
+ ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov); | ||
+ if (ret || GetLastError() != ERROR_IO_PENDING) break; | ||
+ ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE); | ||
+ ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError()); | ||
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); | ||
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError()); | ||
+ ret = FALSE; | ||
+ } | ||
+ if (ret) | ||
+ { | ||
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes); | ||
+ | ||
+ pov = (void *)0xdeadbeef; | ||
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000); | ||
+ ok(!ret, "GetQueuedCompletionStatus succeeded\n"); | ||
+ ok(pov == NULL, "expected NULL, got %p\n", pov); | ||
+ } | ||
+ else | ||
+ win_skip("WriteFile never returned TRUE\n"); | ||
+ | ||
+ CloseHandle(ov.hEvent); | ||
+ CloseHandle(port); | ||
+ CloseHandle(h); | ||
+} | ||
+ | ||
static void test_query_volume_information_file(void) | ||
{ | ||
NTSTATUS status; | ||
@@ -4214,6 +4343,7 @@ START_TEST(file) | ||
test_file_rename_information(); | ||
test_file_link_information(); | ||
test_file_disposition_information(); | ||
+ test_file_completion_information(); | ||
test_query_volume_information_file(); | ||
test_query_attribute_information_file(); | ||
} | ||
diff --git a/include/winternl.h b/include/winternl.h | ||
index f35091c..7613d8b 100644 | ||
--- a/include/winternl.h | ||
+++ b/include/winternl.h | ||
@@ -725,6 +725,14 @@ typedef struct _FILE_ALL_INFORMATION { | ||
FILE_NAME_INFORMATION NameInformation; | ||
} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; | ||
|
||
+typedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION { | ||
+ ULONG Flags; | ||
+} FILE_IO_COMPLETION_NOTIFICATION_INFORMATION, *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION; | ||
+ | ||
+#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 | ||
+#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 | ||
+#define FILE_SKIP_SET_USER_EVENT_ON_FAST_IO 0x4 | ||
+ | ||
typedef enum _FSINFOCLASS { | ||
FileFsVolumeInformation = 1, | ||
FileFsLabelInformation, | ||
diff --git a/server/fd.c b/server/fd.c | ||
index 17b1b66..0d5c7a2 100644 | ||
--- a/server/fd.c | ||
+++ b/server/fd.c | ||
@@ -194,6 +194,7 @@ struct fd | ||
struct async_queue *wait_q; /* other async waiters of this fd */ | ||
struct completion *completion; /* completion object attached to this fd */ | ||
apc_param_t comp_key; /* completion key to set in completion events */ | ||
+ unsigned int comp_flags; /* completion flags */ | ||
}; | ||
|
||
static void fd_dump( struct object *obj, int verbose ); | ||
@@ -1607,6 +1608,7 @@ static struct fd *alloc_fd_object(void) | ||
fd->write_q = NULL; | ||
fd->wait_q = NULL; | ||
fd->completion = NULL; | ||
+ fd->comp_flags = 0; | ||
list_init( &fd->inode_entry ); | ||
list_init( &fd->locks ); | ||
|
||
@@ -2556,12 +2558,29 @@ DECL_HANDLER(add_fd_completion) | ||
struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); | ||
if (fd) | ||
{ | ||
- if (fd->completion) | ||
+ if (fd->completion && (!(fd->comp_flags & COMPLETION_SKIP_ON_SUCCESS) || req->status)) | ||
add_completion( fd->completion, fd->comp_key, req->cvalue, req->status, req->information ); | ||
release_object( fd ); | ||
} | ||
} | ||
|
||
+/* set fd completion information */ | ||
+DECL_HANDLER(set_fd_compl_info) | ||
+{ | ||
+ struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); | ||
+ if (fd) | ||
+ { | ||
+ if (!(fd->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))) | ||
+ { | ||
+ /* removing COMPLETION_SKIP_ON_SUCCESS is not allowed */ | ||
+ fd->comp_flags |= req->flags; | ||
+ } | ||
+ else | ||
+ set_error( STATUS_INVALID_PARAMETER ); | ||
+ release_object( fd ); | ||
+ } | ||
+} | ||
+ | ||
/* set fd disposition information */ | ||
DECL_HANDLER(set_fd_disp_info) | ||
{ | ||
diff --git a/server/protocol.def b/server/protocol.def | ||
index 8d86737..229596a 100644 | ||
--- a/server/protocol.def | ||
+++ b/server/protocol.def | ||
@@ -3678,6 +3678,14 @@ struct handle_info | ||
@END | ||
|
||
|
||
+/* set fd completion information */ | ||
+@REQ(set_fd_compl_info) | ||
+ obj_handle_t handle; /* handle to a file or directory */ | ||
+ int flags; /* completion flags (see below) */ | ||
+@END | ||
+#define COMPLETION_SKIP_ON_SUCCESS 0x01 | ||
+ | ||
+ | ||
/* set fd disposition information */ | ||
@REQ(set_fd_disp_info) | ||
obj_handle_t handle; /* handle to a file or directory */ | ||
-- | ||
2.9.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
Fixes: [38960] Fake success in kernel32.SetFileCompletionNotificationModes | ||
Fixes: [38960] Add support for kernel32.SetFileCompletionNotificationModes |
Oops, something went wrong.