2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32 Kernel Library
4 * FILE: lib/kernel32/file/npipe.c
5 * PURPOSE: Named Pipe Functions
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 * Ariadne ( ariadne@xs4all.nl)
10 /* INCLUDES *******************************************************************/
15 DEBUG_CHANNEL(kernel32file
);
17 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
19 /* GLOBALS ********************************************************************/
23 /* FUNCTIONS ******************************************************************/
30 CreatePipe(PHANDLE hReadPipe
,
32 LPSECURITY_ATTRIBUTES lpPipeAttributes
,
36 UNICODE_STRING PipeName
;
37 OBJECT_ATTRIBUTES ObjectAttributes
;
38 IO_STATUS_BLOCK StatusBlock
;
39 LARGE_INTEGER DefaultTimeout
;
41 HANDLE ReadPipeHandle
;
42 HANDLE WritePipeHandle
;
45 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
47 /* Set the timeout to 120 seconds */
48 DefaultTimeout
.QuadPart
= -1200000000;
50 /* Use default buffer size if desired */
51 if (!nSize
) nSize
= 0x1000;
53 /* Increase the Pipe ID */
54 PipeId
= InterlockedIncrement(&ProcessPipeId
);
56 /* Create the pipe name */
58 L
"\\Device\\NamedPipe\\Win32Pipes.%08x.%08x",
59 NtCurrentTeb()->ClientId
.UniqueProcess
,
61 RtlInitUnicodeString(&PipeName
, Buffer
);
63 /* Always use case insensitive */
64 Attributes
= OBJ_CASE_INSENSITIVE
;
66 /* Check if we got attributes */
69 /* Use the attributes' SD instead */
70 SecurityDescriptor
= lpPipeAttributes
->lpSecurityDescriptor
;
72 /* Set OBJ_INHERIT if requested */
73 if (lpPipeAttributes
->bInheritHandle
) Attributes
|= OBJ_INHERIT
;
76 /* Initialize the attributes */
77 InitializeObjectAttributes(&ObjectAttributes
,
83 /* Create the named pipe */
84 Status
= NtCreateNamedPipeFile(&ReadPipeHandle
,
85 GENERIC_READ
|FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
88 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
90 FILE_SYNCHRONOUS_IO_NONALERT
,
91 FILE_PIPE_BYTE_STREAM_TYPE
,
92 FILE_PIPE_BYTE_STREAM_MODE
,
93 FILE_PIPE_QUEUE_OPERATION
,
98 if (!NT_SUCCESS(Status
))
100 /* Convert error and fail */
101 WARN("Status: %lx\n", Status
);
102 BaseSetLastNTError(Status
);
106 /* Now try opening it for write access */
107 Status
= NtOpenFile(&WritePipeHandle
,
108 FILE_GENERIC_WRITE
| SYNCHRONIZE
,
112 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
113 if (!NT_SUCCESS(Status
))
115 /* Convert error and fail */
116 WARN("Status: %lx\n", Status
);
117 NtClose(ReadPipeHandle
);
118 BaseSetLastNTError(Status
);
122 /* Return both handles */
123 *hReadPipe
= ReadPipeHandle
;
124 *hWritePipe
= WritePipeHandle
;
133 CreateNamedPipeA(LPCSTR lpName
,
137 DWORD nOutBufferSize
,
139 DWORD nDefaultTimeOut
,
140 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
142 /* Call the W(ide) function */
143 ConvertWin32AnsiChangeApiToUnicodeApi(CreateNamedPipe
,
151 lpSecurityAttributes
);
160 CreateNamedPipeW(LPCWSTR lpName
,
164 DWORD nOutBufferSize
,
166 DWORD nDefaultTimeOut
,
167 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
169 UNICODE_STRING NamedPipeName
;
172 OBJECT_ATTRIBUTES ObjectAttributes
;
174 ACCESS_MASK DesiredAccess
;
175 ULONG CreateOptions
= 0;
176 ULONG WriteModeMessage
;
177 ULONG ReadModeMessage
;
179 IO_STATUS_BLOCK Iosb
;
180 ULONG ShareAccess
= 0, Attributes
;
181 LARGE_INTEGER DefaultTimeOut
;
182 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
184 /* Check for valid instances */
185 if (nMaxInstances
== 0 || nMaxInstances
> PIPE_UNLIMITED_INSTANCES
)
188 SetLastError(ERROR_INVALID_PARAMETER
);
189 return INVALID_HANDLE_VALUE
;
192 /* Convert to NT syntax */
193 if (nMaxInstances
== PIPE_UNLIMITED_INSTANCES
)
196 /* Convert the name */
197 Result
= RtlDosPathNameToNtPathName_U(lpName
,
203 /* Conversion failed */
204 SetLastError(ERROR_PATH_NOT_FOUND
);
205 return INVALID_HANDLE_VALUE
;
208 TRACE("Pipe name: %wZ\n", &NamedPipeName
);
209 TRACE("Pipe name: %S\n", NamedPipeName
.Buffer
);
211 /* Always case insensitive, check if we got extra attributes */
212 Attributes
= OBJ_CASE_INSENSITIVE
;
213 if(lpSecurityAttributes
)
215 /* We did; get the security descriptor */
216 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
218 /* And check if this is pipe's handle will beinheritable */
219 if (lpSecurityAttributes
->bInheritHandle
)
220 Attributes
|= OBJ_INHERIT
;
223 /* Now we can initialize the object attributes */
224 InitializeObjectAttributes(&ObjectAttributes
,
230 /* Setup the default Desired Access */
231 DesiredAccess
= SYNCHRONIZE
| (dwOpenMode
& (WRITE_DAC
|
233 ACCESS_SYSTEM_SECURITY
));
235 /* Convert to NT Create Flags */
236 if (dwOpenMode
& FILE_FLAG_WRITE_THROUGH
)
238 CreateOptions
|= FILE_WRITE_THROUGH
;
241 if (!(dwOpenMode
& FILE_FLAG_OVERLAPPED
))
243 CreateOptions
|= FILE_SYNCHRONOUS_IO_NONALERT
;
246 /* Handle all open modes */
247 if (dwOpenMode
& PIPE_ACCESS_OUTBOUND
)
249 ShareAccess
|= FILE_SHARE_READ
;
250 DesiredAccess
|= GENERIC_WRITE
;
253 if (dwOpenMode
& PIPE_ACCESS_INBOUND
)
255 ShareAccess
|= FILE_SHARE_WRITE
;
256 DesiredAccess
|= GENERIC_READ
;
259 /* Handle the type flags */
260 if (dwPipeMode
& PIPE_TYPE_MESSAGE
)
262 WriteModeMessage
= FILE_PIPE_MESSAGE_TYPE
;
266 WriteModeMessage
= FILE_PIPE_BYTE_STREAM_TYPE
;
269 /* Handle the mode flags */
270 if (dwPipeMode
& PIPE_READMODE_MESSAGE
)
272 ReadModeMessage
= FILE_PIPE_MESSAGE_MODE
;
276 ReadModeMessage
= FILE_PIPE_BYTE_STREAM_MODE
;
279 /* Handle the blocking mode */
280 if (dwPipeMode
& PIPE_NOWAIT
)
282 NonBlocking
= FILE_PIPE_COMPLETE_OPERATION
;
286 NonBlocking
= FILE_PIPE_QUEUE_OPERATION
;
289 /* Check if we have a timeout */
292 /* Convert the time to NT format */
293 DefaultTimeOut
.QuadPart
= UInt32x32To64(nDefaultTimeOut
, -10000);
297 /* Use default timeout of 50 ms */
298 DefaultTimeOut
.QuadPart
= -500000;
301 /* Now create the pipe */
302 Status
= NtCreateNamedPipeFile(&PipeHandle
,
317 /* Normalize special error codes */
318 if ((Status
== STATUS_INVALID_DEVICE_REQUEST
) ||
319 (Status
== STATUS_NOT_SUPPORTED
))
321 Status
= STATUS_OBJECT_NAME_INVALID
;
325 RtlFreeHeap(RtlGetProcessHeap(),
327 NamedPipeName
.Buffer
);
330 if (!NT_SUCCESS(Status
))
332 /* Failed to create it */
333 WARN("NtCreateNamedPipe failed (Status %x)!\n", Status
);
334 BaseSetLastNTError (Status
);
335 return INVALID_HANDLE_VALUE
;
338 /* Return the handle */
348 WaitNamedPipeA(LPCSTR lpNamedPipeName
,
352 UNICODE_STRING NameU
;
354 /* Convert the name to Unicode */
355 Basep8BitStringToDynamicUnicodeString(&NameU
, lpNamedPipeName
);
357 /* Call the Unicode API */
358 r
= WaitNamedPipeW(NameU
.Buffer
, nTimeOut
);
360 /* Free the Unicode string */
361 RtlFreeUnicodeString(&NameU
);
369 * When NPFS will work properly, use this code instead. It is compatible with
370 * Microsoft's NPFS.SYS. The main difference is that:
371 * - This code actually respects the timeout instead of ignoring it!
372 * - This code validates and creates the proper names for both UNC and local pipes
373 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
374 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
375 * FILE_PIPE_WAIT_FOR_BUFFER structure.
377 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
383 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
386 UNICODE_STRING NamedPipeName
, NewName
, DevicePath
, PipePrefix
;
391 OBJECT_ATTRIBUTES ObjectAttributes
;
394 IO_STATUS_BLOCK IoStatusBlock
;
395 ULONG WaitPipeInfoSize
;
396 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo
;
398 /* Start by making a unicode string of the name */
399 TRACE("Sent path: %S\n", lpNamedPipeName
);
400 RtlCreateUnicodeString(&NamedPipeName
, lpNamedPipeName
);
401 NameLength
= NamedPipeName
.Length
/ sizeof(WCHAR
);
403 /* All slashes must become backslashes */
404 for (i
= 0; i
< NameLength
; i
++)
406 /* Check and convert */
407 if (NamedPipeName
.Buffer
[i
] == L
'/') NamedPipeName
.Buffer
[i
] = L
'\\';
410 /* Find the path type of the name we were given */
411 NewName
= NamedPipeName
;
412 Type
= RtlDetermineDosPathNameType_U(lpNamedPipeName
);
414 /* Check if this was a device path, ie : "\\.\pipe\name" */
415 if (Type
== RtlPathTypeLocalDevice
)
417 /* Make sure it's a valid prefix */
418 RtlInitUnicodeString(&PipePrefix
, L
"\\\\.\\pipe\\");
419 RtlPrefixString((PANSI_STRING
)&PipePrefix
, (PANSI_STRING
)&NewName
, TRUE
);
423 NewName
.Length
-= 9 * sizeof(WCHAR
);
425 /* Initialize the Dos Devices name */
426 TRACE("NewName: %wZ\n", &NewName
);
427 RtlInitUnicodeString(&DevicePath
, L
"\\DosDevices\\pipe\\");
429 else if (Type
== RtlPathTypeRootLocalDevice
)
431 /* The path is \\server\\pipe\name; find the pipename itself */
432 p
= &NewName
.Buffer
[2];
434 /* First loop to get past the server name */
437 /* Check if this is a backslash */
438 if (*p
== L
'\\') break;
444 /* Now make sure the full name contains "pipe\" */
445 if ((*p
) && !(_wcsnicmp(p
+ 1, L
"pipe\\", sizeof("pipe\\"))))
447 /* Get to the pipe name itself now */
448 p
+= sizeof("pipe\\") - 1;
452 /* The name is invalid */
453 WARN("Invalid name!\n");
454 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD
);
458 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
462 WARN("Invalid path type\n");
463 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD
);
467 /* Now calculate the total length of the structure and allocate it */
468 WaitPipeInfoSize
= FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER
, Name
[0]) +
470 WaitPipeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize
);
471 if (WaitPipeInfo
== NULL
)
473 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
477 /* Initialize the object attributes */
478 TRACE("Opening: %wZ\n", &DevicePath
);
479 InitializeObjectAttributes(&ObjectAttributes
,
481 OBJ_CASE_INSENSITIVE
,
486 Status
= NtOpenFile(&FileHandle
,
487 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
490 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
491 FILE_SYNCHRONOUS_IO_NONALERT
);
492 if (!NT_SUCCESS(Status
))
494 /* Fail; couldn't open */
495 WARN("Status: %lx\n", Status
);
496 BaseSetLastNTError(Status
);
497 RtlFreeUnicodeString(&NamedPipeName
);
498 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
502 /* Check what timeout we got */
503 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
505 /* Don't use a timeout */
506 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
510 /* Check if we should wait forever */
511 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
514 WaitPipeInfo
->Timeout
.LowPart
= 0;
515 WaitPipeInfo
->Timeout
.HighPart
= 0x80000000;
519 /* Convert to NT format */
520 WaitPipeInfo
->Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
523 /* In both cases, we do have a timeout */
524 WaitPipeInfo
->TimeoutSpecified
= TRUE
;
527 /* Set the length and copy the name */
528 WaitPipeInfo
->NameLength
= NewName
.Length
;
529 RtlCopyMemory(WaitPipeInfo
->Name
, NewName
.Buffer
, NewName
.Length
);
531 /* Get rid of the full name */
532 RtlFreeUnicodeString(&NamedPipeName
);
534 /* Let NPFS know of our request */
535 Status
= NtFsControlFile(FileHandle
,
546 /* Free our pipe info data and close the handle */
547 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
550 /* Check the status */
551 if (!NT_SUCCESS(Status
))
553 /* Failure to wait on the pipe */
554 WARN("Status: %lx\n", Status
);
555 BaseSetLastNTError (Status
);
568 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
571 UNICODE_STRING NamedPipeName
;
573 OBJECT_ATTRIBUTES ObjectAttributes
;
574 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
576 IO_STATUS_BLOCK Iosb
;
578 if (RtlDosPathNameToNtPathName_U(lpNamedPipeName
,
586 InitializeObjectAttributes(&ObjectAttributes
,
588 OBJ_CASE_INSENSITIVE
,
591 Status
= NtOpenFile(&FileHandle
,
592 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
595 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
596 FILE_SYNCHRONOUS_IO_NONALERT
);
597 if (!NT_SUCCESS(Status
))
599 BaseSetLastNTError(Status
);
600 RtlFreeUnicodeString(&NamedPipeName
);
604 /* Check what timeout we got */
605 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
607 /* Don't use a timeout */
608 WaitPipe
.TimeoutSpecified
= FALSE
;
612 /* Check if default */
613 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
616 WaitPipe
.Timeout
.LowPart
= 0;
617 WaitPipe
.Timeout
.HighPart
= 0;
621 /* Convert to NT format */
622 WaitPipe
.Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
625 /* In both cases, we do have a timeout */
626 WaitPipe
.TimeoutSpecified
= TRUE
;
629 Status
= NtFsControlFile(FileHandle
,
640 if (!NT_SUCCESS(Status
))
642 BaseSetLastNTError(Status
);
643 RtlFreeUnicodeString(&NamedPipeName
);
647 RtlFreeUnicodeString(&NamedPipeName
);
658 ConnectNamedPipe(IN HANDLE hNamedPipe
,
659 IN LPOVERLAPPED lpOverlapped
)
663 if (lpOverlapped
!= NULL
)
667 lpOverlapped
->Internal
= STATUS_PENDING
;
668 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
670 Status
= NtFsControlFile(hNamedPipe
,
671 lpOverlapped
->hEvent
,
674 (PIO_STATUS_BLOCK
)lpOverlapped
,
681 /* return FALSE in case of failure and pending operations! */
682 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
684 BaseSetLastNTError(Status
);
690 IO_STATUS_BLOCK Iosb
;
692 Status
= NtFsControlFile(hNamedPipe
,
703 /* wait in case operation is pending */
704 if (Status
== STATUS_PENDING
)
706 Status
= NtWaitForSingleObject(hNamedPipe
,
709 if (NT_SUCCESS(Status
))
711 Status
= Iosb
.Status
;
715 if (!NT_SUCCESS(Status
))
717 BaseSetLastNTError(Status
);
731 SetNamedPipeHandleState(HANDLE hNamedPipe
,
733 LPDWORD lpMaxCollectionCount
,
734 LPDWORD lpCollectDataTimeout
)
736 IO_STATUS_BLOCK Iosb
;
739 /* Check if the Mode is being changed */
742 FILE_PIPE_INFORMATION Settings
;
744 /* Set the Completion Mode */
745 Settings
.CompletionMode
= (*lpMode
& PIPE_NOWAIT
) ?
746 FILE_PIPE_COMPLETE_OPERATION
: FILE_PIPE_QUEUE_OPERATION
;
748 /* Set the Read Mode */
749 Settings
.ReadMode
= (*lpMode
& PIPE_READMODE_MESSAGE
) ?
750 FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
752 /* Send the changes to the Driver */
753 Status
= NtSetInformationFile(hNamedPipe
,
756 sizeof(FILE_PIPE_INFORMATION
),
757 FilePipeInformation
);
758 if (!NT_SUCCESS(Status
))
760 BaseSetLastNTError(Status
);
765 /* Check if the Collection count or Timeout are being changed */
766 if (lpMaxCollectionCount
|| lpCollectDataTimeout
)
768 FILE_PIPE_REMOTE_INFORMATION RemoteSettings
;
770 /* Setting one without the other would delete it, so we read old one */
771 if (!lpMaxCollectionCount
|| !lpCollectDataTimeout
)
773 Status
= NtQueryInformationFile(hNamedPipe
,
776 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
777 FilePipeRemoteInformation
);
778 if (!NT_SUCCESS(Status
))
780 BaseSetLastNTError(Status
);
785 /* Now set the new settings */
786 RemoteSettings
.MaximumCollectionCount
= (lpMaxCollectionCount
) ?
787 *lpMaxCollectionCount
:
788 RemoteSettings
.MaximumCollectionCount
;
789 if (lpCollectDataTimeout
)
791 /* Convert it to Quad */
792 RemoteSettings
.CollectDataTime
.QuadPart
=
793 -(LONGLONG
)UInt32x32To64(10000, *lpCollectDataTimeout
);
796 /* Tell the driver to change them */
797 Status
= NtSetInformationFile(hNamedPipe
,
800 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
801 FilePipeRemoteInformation
);
802 if (!NT_SUCCESS(Status
))
804 BaseSetLastNTError(Status
);
818 CallNamedPipeA(LPCSTR lpNamedPipeName
,
822 DWORD nOutBufferSize
,
826 PUNICODE_STRING PipeName
= &NtCurrentTeb()->StaticUnicodeString
;
827 ANSI_STRING AnsiPipe
;
829 /* Initialize the string as ANSI_STRING and convert to Unicode */
830 RtlInitAnsiString(&AnsiPipe
, (LPSTR
)lpNamedPipeName
);
831 RtlAnsiStringToUnicodeString(PipeName
, &AnsiPipe
, FALSE
);
833 /* Call the Unicode function */
834 return CallNamedPipeW(PipeName
->Buffer
,
849 CallNamedPipeW(LPCWSTR lpNamedPipeName
,
853 DWORD nOutBufferSize
,
864 /* Try creating it */
865 hPipe
= CreateFileW(lpNamedPipeName
,
866 GENERIC_READ
| GENERIC_WRITE
,
867 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
870 FILE_ATTRIBUTE_NORMAL
,
873 /* Success, break out */
874 if (hPipe
!= INVALID_HANDLE_VALUE
)
877 /* Already tried twice, give up */
882 WaitNamedPipeW(lpNamedPipeName
, nTimeOut
);
884 /* Get ready to try again */
888 /* Set the pipe mode */
889 dwPipeMode
= PIPE_READMODE_MESSAGE
| PIPE_WAIT
;
890 bError
= SetNamedPipeHandleState(hPipe
, &dwPipeMode
, NULL
, NULL
);
893 /* Couldn't change state, fail */
898 /* Do the transact */
899 bError
= TransactNamedPipe(hPipe
,
907 /* Close the handle */
919 DisconnectNamedPipe(HANDLE hNamedPipe
)
921 IO_STATUS_BLOCK Iosb
;
924 /* Send the FSCTL to the driver */
925 Status
= NtFsControlFile(hNamedPipe
,
930 FSCTL_PIPE_DISCONNECT
,
935 if (Status
== STATUS_PENDING
)
937 /* Wait on NPFS to finish and get updated status */
938 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
939 if (NT_SUCCESS(Status
))
940 Status
= Iosb
.Status
;
943 /* Check for error */
944 if (!NT_SUCCESS(Status
))
947 BaseSetLastNTError(Status
);
960 GetNamedPipeHandleStateW(HANDLE hNamedPipe
,
962 LPDWORD lpCurInstances
,
963 LPDWORD lpMaxCollectionCount
,
964 LPDWORD lpCollectDataTimeout
,
966 DWORD nMaxUserNameSize
)
968 IO_STATUS_BLOCK StatusBlock
;
973 FILE_PIPE_INFORMATION PipeInfo
;
975 Status
= NtQueryInformationFile(hNamedPipe
,
978 sizeof(FILE_PIPE_INFORMATION
),
979 FilePipeInformation
);
980 if (!NT_SUCCESS(Status
))
982 BaseSetLastNTError(Status
);
986 *lpState
= ((PipeInfo
.CompletionMode
!= FILE_PIPE_QUEUE_OPERATION
) ? PIPE_NOWAIT
: PIPE_WAIT
);
987 *lpState
|= ((PipeInfo
.ReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
) ? PIPE_READMODE_MESSAGE
: PIPE_READMODE_BYTE
);
990 if(lpCurInstances
!= NULL
)
992 FILE_PIPE_LOCAL_INFORMATION LocalInfo
;
994 Status
= NtQueryInformationFile(hNamedPipe
,
997 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
998 FilePipeLocalInformation
);
999 if (!NT_SUCCESS(Status
))
1001 BaseSetLastNTError(Status
);
1005 *lpCurInstances
= min(LocalInfo
.CurrentInstances
, PIPE_UNLIMITED_INSTANCES
);
1008 if (lpMaxCollectionCount
!= NULL
|| lpCollectDataTimeout
!= NULL
)
1010 FILE_PIPE_REMOTE_INFORMATION RemoteInfo
;
1012 Status
= NtQueryInformationFile(hNamedPipe
,
1015 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
1016 FilePipeRemoteInformation
);
1017 if (!NT_SUCCESS(Status
))
1019 BaseSetLastNTError(Status
);
1023 if (lpMaxCollectionCount
!= NULL
)
1025 *lpMaxCollectionCount
= RemoteInfo
.MaximumCollectionCount
;
1028 if(lpCollectDataTimeout
!= NULL
)
1031 *lpCollectDataTimeout
= 0;
1035 if (lpUserName
!= NULL
)
1037 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
1038 retreive the user name with GetUserName(), revert the impersonation
1039 and finally restore the thread token */
1051 GetNamedPipeHandleStateA(HANDLE hNamedPipe
,
1053 LPDWORD lpCurInstances
,
1054 LPDWORD lpMaxCollectionCount
,
1055 LPDWORD lpCollectDataTimeout
,
1057 DWORD nMaxUserNameSize
)
1059 UNICODE_STRING UserNameW
= { 0, 0, NULL
};
1060 ANSI_STRING UserNameA
;
1063 if(lpUserName
!= NULL
)
1065 UserNameW
.MaximumLength
= (USHORT
)nMaxUserNameSize
* sizeof(WCHAR
);
1066 UserNameW
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW
.MaximumLength
);
1067 if (UserNameW
.Buffer
== NULL
)
1069 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1073 UserNameA
.Buffer
= lpUserName
;
1074 UserNameA
.Length
= 0;
1075 UserNameA
.MaximumLength
= (USHORT
)nMaxUserNameSize
;
1078 Ret
= GetNamedPipeHandleStateW(hNamedPipe
,
1081 lpMaxCollectionCount
,
1082 lpCollectDataTimeout
,
1085 if (Ret
&& lpUserName
!= NULL
)
1089 RtlInitUnicodeString(&UserNameW
, UserNameW
.Buffer
);
1090 Status
= RtlUnicodeStringToAnsiString(&UserNameA
, &UserNameW
, FALSE
);
1091 if (!NT_SUCCESS(Status
))
1093 BaseSetLastNTError(Status
);
1098 if (UserNameW
.Buffer
!= NULL
)
1100 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW
.Buffer
);
1112 GetNamedPipeInfo(HANDLE hNamedPipe
,
1114 LPDWORD lpOutBufferSize
,
1115 LPDWORD lpInBufferSize
,
1116 LPDWORD lpMaxInstances
)
1118 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation
;
1119 IO_STATUS_BLOCK StatusBlock
;
1122 Status
= NtQueryInformationFile(hNamedPipe
,
1124 &PipeLocalInformation
,
1125 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
1126 FilePipeLocalInformation
);
1127 if (!NT_SUCCESS(Status
))
1129 BaseSetLastNTError(Status
);
1133 if (lpFlags
!= NULL
)
1135 *lpFlags
= (PipeLocalInformation
.NamedPipeEnd
== FILE_PIPE_SERVER_END
) ? PIPE_SERVER_END
: PIPE_CLIENT_END
;
1136 *lpFlags
|= (PipeLocalInformation
.NamedPipeType
== 1) ? PIPE_TYPE_MESSAGE
: PIPE_TYPE_BYTE
;
1139 if (lpOutBufferSize
!= NULL
)
1140 *lpOutBufferSize
= PipeLocalInformation
.OutboundQuota
;
1142 if (lpInBufferSize
!= NULL
)
1143 *lpInBufferSize
= PipeLocalInformation
.InboundQuota
;
1145 if (lpMaxInstances
!= NULL
)
1147 if (PipeLocalInformation
.MaximumInstances
>= 255)
1148 *lpMaxInstances
= PIPE_UNLIMITED_INSTANCES
;
1150 *lpMaxInstances
= PipeLocalInformation
.MaximumInstances
;
1162 PeekNamedPipe(HANDLE hNamedPipe
,
1165 LPDWORD lpBytesRead
,
1166 LPDWORD lpTotalBytesAvail
,
1167 LPDWORD lpBytesLeftThisMessage
)
1169 PFILE_PIPE_PEEK_BUFFER Buffer
;
1170 IO_STATUS_BLOCK Iosb
;
1175 /* Calculate the buffer space that we'll need and allocate it */
1176 BufferSize
= nBufferSize
+ sizeof(FILE_PIPE_PEEK_BUFFER
);
1177 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
1180 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1184 /* Tell the driver to seek */
1185 Status
= NtFsControlFile(hNamedPipe
,
1195 if (Status
== STATUS_PENDING
)
1197 /* Wait for npfs to be done, and update the status */
1198 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
1199 if (NT_SUCCESS(Status
))
1200 Status
= Iosb
.Status
;
1203 /* Overflow is success for us */
1204 if (Status
== STATUS_BUFFER_OVERFLOW
)
1205 Status
= STATUS_SUCCESS
;
1208 if (!NT_SUCCESS(Status
))
1210 /* Free the buffer and return failure */
1211 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1212 BaseSetLastNTError(Status
);
1216 /* Check if caller requested bytes available */
1217 if (lpTotalBytesAvail
)
1218 *lpTotalBytesAvail
= Buffer
->ReadDataAvailable
;
1220 /* Calculate the bytes returned, minus our structure overhead */
1221 BytesRead
= (ULONG
)(Iosb
.Information
-
1222 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1224 /* Check if caller requested bytes read */
1227 /* Return the bytes read */
1228 *lpBytesRead
= BytesRead
;
1231 /* Check if caller requested bytes left */
1232 if (lpBytesLeftThisMessage
)
1234 /* Calculate total minus what we returned and our structure overhead */
1235 *lpBytesLeftThisMessage
= Buffer
->MessageLength
- BytesRead
;
1238 /* Check if the caller wanted to see the actual data */
1241 /* Give him what he wants */
1242 RtlCopyMemory(lpBuffer
,
1247 /* Free the buffer */
1248 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1259 TransactNamedPipe(IN HANDLE hNamedPipe
,
1260 IN LPVOID lpInBuffer
,
1261 IN DWORD nInBufferSize
,
1262 OUT LPVOID lpOutBuffer
,
1263 IN DWORD nOutBufferSize
,
1264 OUT LPDWORD lpBytesRead OPTIONAL
,
1265 IN LPOVERLAPPED lpOverlapped OPTIONAL
)
1269 if (lpBytesRead
!= NULL
)
1274 if (lpOverlapped
!= NULL
)
1278 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
1279 lpOverlapped
->Internal
= STATUS_PENDING
;
1281 Status
= NtFsControlFile(hNamedPipe
,
1282 lpOverlapped
->hEvent
,
1285 (PIO_STATUS_BLOCK
)lpOverlapped
,
1286 FSCTL_PIPE_TRANSCEIVE
,
1291 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1293 BaseSetLastNTError(Status
);
1297 if (lpBytesRead
!= NULL
)
1299 *lpBytesRead
= lpOverlapped
->InternalHigh
;
1304 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1305 IO_STATUS_BLOCK Iosb
;
1307 Status
= NtFsControlFile(hNamedPipe
,
1312 FSCTL_PIPE_TRANSCEIVE
,
1317 if (Status
== STATUS_PENDING
)
1319 Status
= NtWaitForSingleObject(hNamedPipe
,
1322 if (NT_SUCCESS(Status
))
1323 Status
= Iosb
.Status
;
1326 if (NT_SUCCESS(Status
))
1328 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1329 check that case either and crashes (only after the operation
1331 *lpBytesRead
= Iosb
.Information
;
1335 BaseSetLastNTError(Status
);
1338 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1341 while (0 != nInBufferSize
&&
1342 WriteFile(hNamedPipe
, lpInBuffer
, nInBufferSize
, &nActualBytes
,
1345 lpInBuffer
= (LPVOID
)((char *) lpInBuffer
+ nActualBytes
);
1346 nInBufferSize
-= nActualBytes
;
1349 if (0 != nInBufferSize
)
1351 /* Must have dropped out of the while 'cause WriteFile failed */
1355 if (!ReadFile(hNamedPipe
, lpOutBuffer
, nOutBufferSize
, &nActualBytes
,
1361 if (NULL
!= lpBytesRead
)
1363 *lpBytesRead
= nActualBytes
;