static void test_create(void) { HANDLE hserver; NTSTATUS res; int j, k; FILE_PIPE_LOCAL_INFORMATION info; IO_STATUS_BLOCK iosb; static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE}; static const DWORD sharing[] = { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE }; static const DWORD pipe_config[]= { 1, 0, 2 }; for (j = 0; j < sizeof(sharing) / sizeof(DWORD); j++) { for (k = 0; k < sizeof(access) / sizeof(DWORD); k++) { HANDLE hclient; BOOL should_succeed = TRUE; res = create_pipe(&hserver, sharing[j], FILE_SYNCHRONOUS_IO_NONALERT); if (res) { ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]); continue; } res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24); ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]); ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n", info.NamedPipeConfiguration, pipe_config[j]); hclient = CreateFileW(testpipe, access[k], 0, 0, OPEN_EXISTING, 0, 0); if (hclient != INVALID_HANDLE_VALUE) { res = pNtQueryInformationFile(hclient, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24); ok(!res, "NtQueryInformationFile for client returned %x, access: %x, sharing: %x\n", res, access[k], sharing[j]); ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n", info.NamedPipeConfiguration, pipe_config[j]); CloseHandle(hclient); } if (access[k] & GENERIC_WRITE) should_succeed &= !!(sharing[j] & FILE_SHARE_WRITE); if (access[k] & GENERIC_READ) should_succeed &= !!(sharing[j] & FILE_SHARE_READ); if (should_succeed) ok(hclient != INVALID_HANDLE_VALUE, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n", sharing[j], access[k], GetLastError()); else ok(hclient == INVALID_HANDLE_VALUE, "CreateFile succeeded for sharing %x, access: %x\n", sharing[j], access[k]); CloseHandle(hserver); } } }
static void test_create_invalid(void) { IO_STATUS_BLOCK iosb; OBJECT_ATTRIBUTES attr; UNICODE_STRING name; LARGE_INTEGER timeout; NTSTATUS res; HANDLE handle, handle2; FILE_PIPE_LOCAL_INFORMATION info; pRtlInitUnicodeString(&name, testpipe_nt); attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.ObjectName = &name; attr.Attributes = 0x40; /*case insensitive */ attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; timeout.QuadPart = -100000000000ll; /* create a pipe with FILE_OVERWRITE */ res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 4 /*FILE_OVERWRITE*/, 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res); if (!res) CloseHandle(handle); /* create a pipe with FILE_OVERWRITE_IF */ res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 5 /*FILE_OVERWRITE_IF*/, 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res); if (!res) CloseHandle(handle); /* create a pipe with sharing = 0 */ res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/, 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res); if (!res) CloseHandle(handle); /* create a pipe without r/w access */ res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/, 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); ok(!res, "NtCreateNamedPipeFile returned %x\n", res); res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24); ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res); /* test FILE_CREATE creation disposition */ res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/, 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout); todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res); if (!res) CloseHandle(handle2); CloseHandle(handle); }
static void _check_pipe_handle_state(int line, HANDLE handle, ULONG read, ULONG completion) { IO_STATUS_BLOCK iosb; FILE_PIPE_INFORMATION fpi; NTSTATUS res; if (handle != INVALID_HANDLE_VALUE) { memset(&fpi, 0x55, sizeof(fpi)); res = pNtQueryInformationFile(handle, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok_(__FILE__, line)(!res, "NtQueryInformationFile returned %x\n", res); ok_(__FILE__, line)(fpi.ReadMode == read, "Unexpected ReadMode, expected %x, got %x\n", read, fpi.ReadMode); ok_(__FILE__, line)(fpi.CompletionMode == completion, "Unexpected CompletionMode, expected %x, got %x\n", completion, fpi.CompletionMode); } }
static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle, HANDLE pipeHandle, DWORD duplex_flags) { NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_MODE_INFORMATION mode_info; DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { /* If this returns ERROR_INVALID_PARAMETER we probably opened something */ /* that is not a pipe. */ if (GetLastError() == ERROR_INVALID_PARAMETER) { SetLastError(WSAENOTSOCK); } return -1; } /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */ nt_status = pNtQueryInformationFile(pipeHandle, &io_status, &mode_info, sizeof(mode_info), FileModeInformation); if (nt_status != STATUS_SUCCESS) { return -1; } if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { /* Non-overlapped pipe. */ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE; } else { /* Overlapped pipe. Try to associate with IOCP. */ if (CreateIoCompletionPort(pipeHandle, loop->iocp, (ULONG_PTR)handle, 0) == NULL) { handle->flags |= UV_HANDLE_EMULATE_IOCP; } } handle->handle = pipeHandle; handle->flags |= duplex_flags; return 0; }
void fs__fchmod(uv_fs_t* req, uv_file file, int mode) { int result; HANDLE handle; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_BASIC_INFORMATION file_info; handle = (HANDLE)_get_osfhandle(file); nt_status = pNtQueryInformationFile(handle, &io_status, &file_info, sizeof file_info, FileBasicInformation); if (nt_status != STATUS_SUCCESS) { result = -1; goto done; } if (mode & _S_IWRITE) { file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; } else { file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; } nt_status = pNtSetInformationFile(handle, &io_status, &file_info, sizeof file_info, FileBasicInformation); if (nt_status != STATUS_SUCCESS) { result = -1; goto done; } result = 0; done: SET_REQ_RESULT(req, result); }
static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle, HANDLE pipeHandle) { NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_MODE_INFORMATION mode_info; DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { return -1; } /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */ nt_status = pNtQueryInformationFile(pipeHandle, &io_status, &mode_info, sizeof(mode_info), FileModeInformation); if (nt_status != STATUS_SUCCESS) { return -1; } if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { /* Non-overlapped pipe. */ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE; } else { /* Overlapped pipe. Try to associate with IOCP. */ if (CreateIoCompletionPort(pipeHandle, loop->iocp, (ULONG_PTR)handle, 0) == NULL) { handle->flags |= UV_HANDLE_EMULATE_IOCP; } } return 0; }
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { DWORD result; uv_shutdown_t* req; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_PIPE_LOCAL_INFORMATION pipe_info; if ((handle->flags & UV_HANDLE_CONNECTION) && handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { req = handle->shutdown_req; /* Clear the shutdown_req field so we don't go here again. */ handle->shutdown_req = NULL; if (handle->flags & UV__HANDLE_CLOSING) { UNREGISTER_HANDLE_REQ(loop, handle, req); /* Already closing. Cancel the shutdown. */ if (req->cb) { uv__set_artificial_error(loop, UV_ECANCELED); req->cb(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); return; } /* Try to avoid flushing the pipe buffer in the thread pool. */ nt_status = pNtQueryInformationFile(handle->handle, &io_status, &pipe_info, sizeof pipe_info, FilePipeLocalInformation); if (nt_status != STATUS_SUCCESS) { /* Failure */ UNREGISTER_HANDLE_REQ(loop, handle, req); handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ if (req->cb) { uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status)); req->cb(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); return; } if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { /* Short-circuit, no need to call FlushFileBuffers. */ uv_insert_pending_req(loop, (uv_req_t*) req); return; } /* Run FlushFileBuffers in the thread pool. */ result = QueueUserWorkItem(pipe_shutdown_thread_proc, req, WT_EXECUTELONGFUNCTION); if (result) { return; } else { /* Failure. */ UNREGISTER_HANDLE_REQ(loop, handle, req); handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ if (req->cb) { uv__set_sys_error(loop, GetLastError()); req->cb(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); return; } } if (handle->flags & UV__HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); if (handle->flags & UV_HANDLE_CONNECTION) { if (handle->pending_ipc_info.socket_info) { free(handle->pending_ipc_info.socket_info); handle->pending_ipc_info.socket_info = NULL; } if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(handle->read_req.wait_handle); handle->read_req.wait_handle = INVALID_HANDLE_VALUE; } if (handle->read_req.event_handle) { CloseHandle(handle->read_req.event_handle); handle->read_req.event_handle = NULL; } } } if (handle->flags & UV_HANDLE_PIPESERVER) { assert(handle->accept_reqs); free(handle->accept_reqs); handle->accept_reqs = NULL; } uv__handle_close(handle); } }
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { unsigned int uv_alloced; DWORD result; uv_shutdown_t* req; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_PIPE_LOCAL_INFORMATION pipe_info; if (handle->flags & UV_HANDLE_SHUTTING && !(handle->flags & UV_HANDLE_SHUT) && handle->write_reqs_pending == 0) { req = handle->shutdown_req; /* Try to avoid flushing the pipe buffer in the thread pool. */ nt_status = pNtQueryInformationFile(handle->handle, &io_status, &pipe_info, sizeof pipe_info, FilePipeLocalInformation); if (nt_status != STATUS_SUCCESS) { /* Failure */ handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status)); req->cb(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); return; } if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { handle->flags |= UV_HANDLE_SHUT; /* Short-circuit, no need to call FlushFileBuffers. */ uv_insert_pending_req(loop, (uv_req_t*) req); return; } /* Run FlushFileBuffers in the thread pool. */ result = QueueUserWorkItem(pipe_shutdown_thread_proc, req, WT_EXECUTELONGFUNCTION); if (result) { /* Mark the handle as shut now to avoid going through this again. */ handle->flags |= UV_HANDLE_SHUT; return; } else { /* Failure. */ handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, GetLastError()); req->cb(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); return; } } if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; if (handle->flags & UV_HANDLE_CONNECTION) { if (handle->pending_socket_info) { free(handle->pending_socket_info); handle->pending_socket_info = NULL; } if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(handle->read_req.wait_handle); handle->read_req.wait_handle = INVALID_HANDLE_VALUE; } if (handle->read_req.event_handle) { CloseHandle(handle->read_req.event_handle); handle->read_req.event_handle = NULL; } } } if (handle->flags & UV_HANDLE_PIPESERVER) { assert(handle->accept_reqs); free(handle->accept_reqs); handle->accept_reqs = NULL; } /* Remember the state of this flag because the close callback is */ /* allowed to clobber or free the handle's memory */ uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED; if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } if (uv_alloced) { free(handle); } uv_unref(loop); } }
uint32_t path_from_handle(HANDLE handle, wchar_t *path, uint32_t path_buffer_len) { static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)( _In_ HANDLE FileHandle, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _Out_ PVOID FsInformation, _In_ ULONG Length, _In_ FS_INFORMATION_CLASS FsInformationClass ); if(pNtQueryVolumeInformationFile == NULL) { *(FARPROC *) &pNtQueryVolumeInformationFile = GetProcAddress( GetModuleHandle("ntdll"), "NtQueryVolumeInformationFile"); } static NTSTATUS (WINAPI *pNtQueryInformationFile)( _In_ HANDLE FileHandle, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _Out_ PVOID FileInformation, _In_ ULONG Length, _In_ FILE_INFORMATION_CLASS FileInformationClass ); if(pNtQueryInformationFile == NULL) { *(FARPROC *) &pNtQueryInformationFile = GetProcAddress( GetModuleHandle("ntdll"), "NtQueryInformationFile"); } IO_STATUS_BLOCK status = {}; FILE_FS_VOLUME_INFORMATION volume_information; unsigned char buf[FILE_NAME_INFORMATION_REQUIRED_SIZE]; FILE_NAME_INFORMATION *name_information = (FILE_NAME_INFORMATION *) buf; // get the volume serial number of the directory handle if(NT_SUCCESS(pNtQueryVolumeInformationFile(handle, &status, &volume_information, sizeof(volume_information), FileFsVolumeInformation)) == 0) { return 0; } unsigned long serial_number; // enumerate all harddisks in order to find the // corresponding serial number wcscpy(path, L"?:\\"); for (path[0] = 'A'; path[0] <= 'Z'; path[0]++) { if(GetVolumeInformationW(path, NULL, 0, &serial_number, NULL, NULL, NULL, 0) == 0 || serial_number != volume_information.VolumeSerialNumber) { continue; } // obtain the relative path for this filename on the given harddisk if(NT_SUCCESS(pNtQueryInformationFile(handle, &status, name_information, FILE_NAME_INFORMATION_REQUIRED_SIZE, FileNameInformation))) { uint32_t length = name_information->FileNameLength / sizeof(wchar_t); // NtQueryInformationFile omits the "C:" part in a // filename, apparently wcsncpy(path + 2, name_information->FileName, path_buffer_len - 2); return length + 2 < path_buffer_len ? length + 2 : path_buffer_len - 1; } } return 0; }
static void test_filepipeinfo(void) { IO_STATUS_BLOCK iosb; OBJECT_ATTRIBUTES attr; UNICODE_STRING name; LARGE_INTEGER timeout; HANDLE hServer, hClient; FILE_PIPE_INFORMATION fpi; NTSTATUS res; pRtlInitUnicodeString(&name, testpipe_nt); attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.ObjectName = &name; attr.Attributes = 0x40; /* case insensitive */ attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; timeout.QuadPart = -100000000000ll; /* test with INVALID_HANDLE_VALUE */ res = pNtQueryInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtQueryInformationFile returned %x\n", res); fpi.ReadMode = 0; fpi.CompletionMode = 0; res = pNtSetInformationFile(INVALID_HANDLE_VALUE, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_OBJECT_TYPE_MISMATCH, "NtSetInformationFile returned %x\n", res); /* server end with read-only attributes */ res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */, 0, 0, 0, 1, 0xFFFFFFFF, 500, 500, &timeout); ok(!res, "NtCreateNamedPipeFile returned %x\n", res); check_pipe_handle_state(hServer, 0, 1); hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError()); check_pipe_handle_state(hServer, 0, 1); check_pipe_handle_state(hClient, 0, 0); fpi.ReadMode = 0; fpi.CompletionMode = 0; res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res); check_pipe_handle_state(hServer, 0, 1); check_pipe_handle_state(hClient, 0, 0); fpi.ReadMode = 1; /* invalid on a byte stream pipe */ fpi.CompletionMode = 1; res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res); check_pipe_handle_state(hServer, 0, 1); check_pipe_handle_state(hClient, 0, 0); if (hClient != INVALID_HANDLE_VALUE) { fpi.ReadMode = 1; /* invalid on a byte stream pipe */ fpi.CompletionMode = 1; res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_INVALID_PARAMETER, "NtSetInformationFile returned %x\n", res); } check_pipe_handle_state(hServer, 0, 1); check_pipe_handle_state(hClient, 0, 0); if (hClient != INVALID_HANDLE_VALUE) { fpi.ReadMode = 0; fpi.CompletionMode = 1; res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(!res, "NtSetInformationFile returned %x\n", res); } check_pipe_handle_state(hServer, 0, 1); check_pipe_handle_state(hClient, 0, 1); if (hClient != INVALID_HANDLE_VALUE) { fpi.ReadMode = 0; fpi.CompletionMode = 2; /* not in range 0-1 */ res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res); fpi.ReadMode = 2; /* not in range 0-1 */ fpi.CompletionMode = 0; res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res); } CloseHandle(hClient); check_pipe_handle_state(hServer, 0, 1); fpi.ReadMode = 0; fpi.CompletionMode = 0; res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_ACCESS_DENIED, "NtSetInformationFile returned %x\n", res); CloseHandle(hServer); /* message mode server with read/write attributes */ res = pNtCreateNamedPipeFile(&hServer, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /* FILE_CREATE */, 0, 1, 1, 0, 0xFFFFFFFF, 500, 500, &timeout); ok(!res, "NtCreateNamedPipeFile returned %x\n", res); check_pipe_handle_state(hServer, 1, 0); hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError()); check_pipe_handle_state(hServer, 1, 0); check_pipe_handle_state(hClient, 0, 0); if (hClient != INVALID_HANDLE_VALUE) { fpi.ReadMode = 1; fpi.CompletionMode = 1; res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(!res, "NtSetInformationFile returned %x\n", res); } check_pipe_handle_state(hServer, 1, 0); check_pipe_handle_state(hClient, 1, 1); fpi.ReadMode = 0; fpi.CompletionMode = 1; res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(!res, "NtSetInformationFile returned %x\n", res); check_pipe_handle_state(hServer, 0, 1); check_pipe_handle_state(hClient, 1, 1); if (hClient != INVALID_HANDLE_VALUE) { fpi.ReadMode = 0; fpi.CompletionMode = 2; /* not in range 0-1 */ res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res); fpi.ReadMode = 2; /* not in range 0-1 */ fpi.CompletionMode = 0; res = pNtSetInformationFile(hClient, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(res == STATUS_INVALID_PARAMETER || broken(!res) /* < Vista */, "NtSetInformationFile returned %x\n", res); } CloseHandle(hClient); check_pipe_handle_state(hServer, 0, 1); fpi.ReadMode = 1; fpi.CompletionMode = 0; res = pNtSetInformationFile(hServer, &iosb, &fpi, sizeof(fpi), (FILE_INFORMATION_CLASS)23); ok(!res, "NtSetInformationFile returned %x\n", res); check_pipe_handle_state(hServer, 1, 0); CloseHandle(hServer); }