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 /* FUNCTIONS ****************************************************************/
26 CreateNamedPipeA(LPCSTR lpName
,
32 DWORD nDefaultTimeOut
,
33 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
35 /* Call the W(ide) function */
36 ConvertWin32AnsiChangeApiToUnicodeApi(CreateNamedPipe
,
44 lpSecurityAttributes
);
53 CreateNamedPipeW(LPCWSTR lpName
,
59 DWORD nDefaultTimeOut
,
60 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
62 UNICODE_STRING NamedPipeName
;
65 OBJECT_ATTRIBUTES ObjectAttributes
;
67 ACCESS_MASK DesiredAccess
;
68 ULONG CreateOptions
= 0;
69 ULONG WriteModeMessage
;
70 ULONG ReadModeMessage
;
73 ULONG ShareAccess
= 0, Attributes
;
74 LARGE_INTEGER DefaultTimeOut
;
75 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
77 /* Check for valid instances */
78 if (nMaxInstances
== 0 || nMaxInstances
> PIPE_UNLIMITED_INSTANCES
)
81 SetLastError(ERROR_INVALID_PARAMETER
);
82 return INVALID_HANDLE_VALUE
;
85 /* Convert to NT syntax */
86 if (nMaxInstances
== PIPE_UNLIMITED_INSTANCES
)
89 /* Convert the name */
90 Result
= RtlDosPathNameToNtPathName_U(lpName
,
96 /* Conversion failed */
97 SetLastError(ERROR_PATH_NOT_FOUND
);
98 return INVALID_HANDLE_VALUE
;
101 TRACE("Pipe name: %wZ\n", &NamedPipeName
);
102 TRACE("Pipe name: %S\n", NamedPipeName
.Buffer
);
104 /* Always case insensitive, check if we got extra attributes */
105 Attributes
= OBJ_CASE_INSENSITIVE
;
106 if(lpSecurityAttributes
)
108 /* We did; get the security descriptor */
109 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
111 /* And check if this is pipe's handle will beinheritable */
112 if (lpSecurityAttributes
->bInheritHandle
)
113 Attributes
|= OBJ_INHERIT
;
116 /* Now we can initialize the object attributes */
117 InitializeObjectAttributes(&ObjectAttributes
,
123 /* Setup the default Desired Access */
124 DesiredAccess
= SYNCHRONIZE
| (dwOpenMode
& (WRITE_DAC
|
126 ACCESS_SYSTEM_SECURITY
));
128 /* Convert to NT Create Flags */
129 if (dwOpenMode
& FILE_FLAG_WRITE_THROUGH
)
131 CreateOptions
|= FILE_WRITE_THROUGH
;
134 if (!(dwOpenMode
& FILE_FLAG_OVERLAPPED
))
136 CreateOptions
|= FILE_SYNCHRONOUS_IO_NONALERT
;
139 /* Handle all open modes */
140 if (dwOpenMode
& PIPE_ACCESS_OUTBOUND
)
142 ShareAccess
|= FILE_SHARE_READ
;
143 DesiredAccess
|= GENERIC_WRITE
;
146 if (dwOpenMode
& PIPE_ACCESS_INBOUND
)
148 ShareAccess
|= FILE_SHARE_WRITE
;
149 DesiredAccess
|= GENERIC_READ
;
152 /* Handle the type flags */
153 if (dwPipeMode
& PIPE_TYPE_MESSAGE
)
155 WriteModeMessage
= FILE_PIPE_MESSAGE_TYPE
;
159 WriteModeMessage
= FILE_PIPE_BYTE_STREAM_TYPE
;
162 /* Handle the mode flags */
163 if (dwPipeMode
& PIPE_READMODE_MESSAGE
)
165 ReadModeMessage
= FILE_PIPE_MESSAGE_MODE
;
169 ReadModeMessage
= FILE_PIPE_BYTE_STREAM_MODE
;
172 /* Handle the blocking mode */
173 if (dwPipeMode
& PIPE_NOWAIT
)
175 NonBlocking
= FILE_PIPE_COMPLETE_OPERATION
;
179 NonBlocking
= FILE_PIPE_QUEUE_OPERATION
;
182 /* Check if we have a timeout */
185 /* Convert the time to NT format */
186 DefaultTimeOut
.QuadPart
= UInt32x32To64(nDefaultTimeOut
, -10000);
190 /* Use default timeout of 50 ms */
191 DefaultTimeOut
.QuadPart
= -500000;
194 /* Now create the pipe */
195 Status
= NtCreateNamedPipeFile(&PipeHandle
,
210 /* Normalize special error codes */
211 if ((Status
== STATUS_INVALID_DEVICE_REQUEST
) ||
212 (Status
== STATUS_NOT_SUPPORTED
))
214 Status
= STATUS_OBJECT_NAME_INVALID
;
218 RtlFreeHeap(RtlGetProcessHeap(),
220 NamedPipeName
.Buffer
);
223 if (!NT_SUCCESS(Status
))
225 /* Failed to create it */
226 WARN("NtCreateNamedPipe failed (Status %x)!\n", Status
);
227 BaseSetLastNTError (Status
);
228 return INVALID_HANDLE_VALUE
;
231 /* Return the handle */
241 WaitNamedPipeA(LPCSTR lpNamedPipeName
,
245 UNICODE_STRING NameU
;
247 /* Convert the name to Unicode */
248 Basep8BitStringToDynamicUnicodeString(&NameU
, lpNamedPipeName
);
250 /* Call the Unicode API */
251 r
= WaitNamedPipeW(NameU
.Buffer
, nTimeOut
);
253 /* Free the Unicode string */
254 RtlFreeUnicodeString(&NameU
);
262 * When NPFS will work properly, use this code instead. It is compatible with
263 * Microsoft's NPFS.SYS. The main difference is that:
264 * - This code actually respects the timeout instead of ignoring it!
265 * - This code validates and creates the proper names for both UNC and local pipes
266 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
267 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
268 * FILE_PIPE_WAIT_FOR_BUFFER structure.
270 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
276 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
279 UNICODE_STRING NamedPipeName
, NewName
, DevicePath
, PipePrefix
;
284 OBJECT_ATTRIBUTES ObjectAttributes
;
287 IO_STATUS_BLOCK IoStatusBlock
;
288 ULONG WaitPipeInfoSize
;
289 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo
;
291 /* Start by making a unicode string of the name */
292 TRACE("Sent path: %S\n", lpNamedPipeName
);
293 RtlCreateUnicodeString(&NamedPipeName
, lpNamedPipeName
);
294 NameLength
= NamedPipeName
.Length
/ sizeof(WCHAR
);
296 /* All slashes must become backslashes */
297 for (i
= 0; i
< NameLength
; i
++)
299 /* Check and convert */
300 if (NamedPipeName
.Buffer
[i
] == L
'/') NamedPipeName
.Buffer
[i
] = L
'\\';
303 /* Find the path type of the name we were given */
304 NewName
= NamedPipeName
;
305 Type
= RtlDetermineDosPathNameType_U(lpNamedPipeName
);
307 /* Check if this was a device path, ie : "\\.\pipe\name" */
308 if (Type
== RtlPathTypeLocalDevice
)
310 /* Make sure it's a valid prefix */
311 RtlInitUnicodeString(&PipePrefix
, L
"\\\\.\\pipe\\");
312 RtlPrefixString((PANSI_STRING
)&PipePrefix
, (PANSI_STRING
)&NewName
, TRUE
);
316 NewName
.Length
-= 9 * sizeof(WCHAR
);
318 /* Initialize the Dos Devices name */
319 TRACE("NewName: %wZ\n", &NewName
);
320 RtlInitUnicodeString(&DevicePath
, L
"\\DosDevices\\pipe\\");
322 else if (Type
== RtlPathTypeRootLocalDevice
)
324 /* The path is \\server\\pipe\name; find the pipename itself */
325 p
= &NewName
.Buffer
[2];
327 /* First loop to get past the server name */
330 /* Check if this is a backslash */
331 if (*p
== L
'\\') break;
337 /* Now make sure the full name contains "pipe\" */
338 if ((*p
) && !(_wcsnicmp(p
+ 1, L
"pipe\\", sizeof("pipe\\"))))
340 /* Get to the pipe name itself now */
341 p
+= sizeof("pipe\\") - 1;
345 /* The name is invalid */
346 WARN("Invalid name!\n");
347 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD
);
351 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
355 WARN("Invalid path type\n");
356 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD
);
360 /* Now calculate the total length of the structure and allocate it */
361 WaitPipeInfoSize
= FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER
, Name
[0]) +
363 WaitPipeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize
);
364 if (WaitPipeInfo
== NULL
)
366 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
370 /* Initialize the object attributes */
371 TRACE("Opening: %wZ\n", &DevicePath
);
372 InitializeObjectAttributes(&ObjectAttributes
,
374 OBJ_CASE_INSENSITIVE
,
379 Status
= NtOpenFile(&FileHandle
,
380 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
383 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
384 FILE_SYNCHRONOUS_IO_NONALERT
);
385 if (!NT_SUCCESS(Status
))
387 /* Fail; couldn't open */
388 WARN("Status: %lx\n", Status
);
389 BaseSetLastNTError(Status
);
390 RtlFreeUnicodeString(&NamedPipeName
);
391 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
395 /* Check what timeout we got */
396 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
398 /* Don't use a timeout */
399 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
403 /* Check if we should wait forever */
404 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
407 WaitPipeInfo
->Timeout
.LowPart
= 0;
408 WaitPipeInfo
->Timeout
.HighPart
= 0x80000000;
412 /* Convert to NT format */
413 WaitPipeInfo
->Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
416 /* In both cases, we do have a timeout */
417 WaitPipeInfo
->TimeoutSpecified
= TRUE
;
420 /* Set the length and copy the name */
421 WaitPipeInfo
->NameLength
= NewName
.Length
;
422 RtlCopyMemory(WaitPipeInfo
->Name
, NewName
.Buffer
, NewName
.Length
);
424 /* Get rid of the full name */
425 RtlFreeUnicodeString(&NamedPipeName
);
427 /* Let NPFS know of our request */
428 Status
= NtFsControlFile(FileHandle
,
439 /* Free our pipe info data and close the handle */
440 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
443 /* Check the status */
444 if (!NT_SUCCESS(Status
))
446 /* Failure to wait on the pipe */
447 WARN("Status: %lx\n", Status
);
448 BaseSetLastNTError (Status
);
461 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
464 UNICODE_STRING NamedPipeName
;
466 OBJECT_ATTRIBUTES ObjectAttributes
;
467 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
469 IO_STATUS_BLOCK Iosb
;
471 if (RtlDosPathNameToNtPathName_U(lpNamedPipeName
,
479 InitializeObjectAttributes(&ObjectAttributes
,
481 OBJ_CASE_INSENSITIVE
,
484 Status
= NtOpenFile(&FileHandle
,
485 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
488 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
489 FILE_SYNCHRONOUS_IO_NONALERT
);
490 if (!NT_SUCCESS(Status
))
492 BaseSetLastNTError(Status
);
493 RtlFreeUnicodeString(&NamedPipeName
);
497 /* Check what timeout we got */
498 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
500 /* Don't use a timeout */
501 WaitPipe
.TimeoutSpecified
= FALSE
;
505 /* Check if default */
506 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
509 WaitPipe
.Timeout
.LowPart
= 0;
510 WaitPipe
.Timeout
.HighPart
= 0;
514 /* Convert to NT format */
515 WaitPipe
.Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
518 /* In both cases, we do have a timeout */
519 WaitPipe
.TimeoutSpecified
= TRUE
;
522 Status
= NtFsControlFile(FileHandle
,
533 if (!NT_SUCCESS(Status
))
535 BaseSetLastNTError(Status
);
536 RtlFreeUnicodeString(&NamedPipeName
);
540 RtlFreeUnicodeString(&NamedPipeName
);
551 ConnectNamedPipe(IN HANDLE hNamedPipe
,
552 IN LPOVERLAPPED lpOverlapped
)
556 if (lpOverlapped
!= NULL
)
560 lpOverlapped
->Internal
= STATUS_PENDING
;
561 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
563 Status
= NtFsControlFile(hNamedPipe
,
564 lpOverlapped
->hEvent
,
567 (PIO_STATUS_BLOCK
)lpOverlapped
,
574 /* return FALSE in case of failure and pending operations! */
575 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
577 BaseSetLastNTError(Status
);
583 IO_STATUS_BLOCK Iosb
;
585 Status
= NtFsControlFile(hNamedPipe
,
596 /* wait in case operation is pending */
597 if (Status
== STATUS_PENDING
)
599 Status
= NtWaitForSingleObject(hNamedPipe
,
602 if (NT_SUCCESS(Status
))
604 Status
= Iosb
.Status
;
608 if (!NT_SUCCESS(Status
))
610 BaseSetLastNTError(Status
);
624 SetNamedPipeHandleState(HANDLE hNamedPipe
,
626 LPDWORD lpMaxCollectionCount
,
627 LPDWORD lpCollectDataTimeout
)
629 IO_STATUS_BLOCK Iosb
;
632 /* Check if the Mode is being changed */
635 FILE_PIPE_INFORMATION Settings
;
637 /* Set the Completion Mode */
638 Settings
.CompletionMode
= (*lpMode
& PIPE_NOWAIT
) ?
639 FILE_PIPE_COMPLETE_OPERATION
: FILE_PIPE_QUEUE_OPERATION
;
641 /* Set the Read Mode */
642 Settings
.ReadMode
= (*lpMode
& PIPE_READMODE_MESSAGE
) ?
643 FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
645 /* Send the changes to the Driver */
646 Status
= NtSetInformationFile(hNamedPipe
,
649 sizeof(FILE_PIPE_INFORMATION
),
650 FilePipeInformation
);
651 if (!NT_SUCCESS(Status
))
653 BaseSetLastNTError(Status
);
658 /* Check if the Collection count or Timeout are being changed */
659 if (lpMaxCollectionCount
|| lpCollectDataTimeout
)
661 FILE_PIPE_REMOTE_INFORMATION RemoteSettings
;
663 /* Setting one without the other would delete it, so we read old one */
664 if (!lpMaxCollectionCount
|| !lpCollectDataTimeout
)
666 Status
= NtQueryInformationFile(hNamedPipe
,
669 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
670 FilePipeRemoteInformation
);
671 if (!NT_SUCCESS(Status
))
673 BaseSetLastNTError(Status
);
678 /* Now set the new settings */
679 RemoteSettings
.MaximumCollectionCount
= (lpMaxCollectionCount
) ?
680 *lpMaxCollectionCount
:
681 RemoteSettings
.MaximumCollectionCount
;
682 if (lpCollectDataTimeout
)
684 /* Convert it to Quad */
685 RemoteSettings
.CollectDataTime
.QuadPart
=
686 -(LONGLONG
)UInt32x32To64(10000, *lpCollectDataTimeout
);
689 /* Tell the driver to change them */
690 Status
= NtSetInformationFile(hNamedPipe
,
693 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
694 FilePipeRemoteInformation
);
695 if (!NT_SUCCESS(Status
))
697 BaseSetLastNTError(Status
);
711 CallNamedPipeA(LPCSTR lpNamedPipeName
,
715 DWORD nOutBufferSize
,
719 PUNICODE_STRING PipeName
= &NtCurrentTeb()->StaticUnicodeString
;
720 ANSI_STRING AnsiPipe
;
722 /* Initialize the string as ANSI_STRING and convert to Unicode */
723 RtlInitAnsiString(&AnsiPipe
, (LPSTR
)lpNamedPipeName
);
724 RtlAnsiStringToUnicodeString(PipeName
, &AnsiPipe
, FALSE
);
726 /* Call the Unicode function */
727 return CallNamedPipeW(PipeName
->Buffer
,
742 CallNamedPipeW(LPCWSTR lpNamedPipeName
,
746 DWORD nOutBufferSize
,
757 /* Try creating it */
758 hPipe
= CreateFileW(lpNamedPipeName
,
759 GENERIC_READ
| GENERIC_WRITE
,
760 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
763 FILE_ATTRIBUTE_NORMAL
,
766 /* Success, break out */
767 if (hPipe
!= INVALID_HANDLE_VALUE
)
770 /* Already tried twice, give up */
775 WaitNamedPipeW(lpNamedPipeName
, nTimeOut
);
777 /* Get ready to try again */
781 /* Set the pipe mode */
782 dwPipeMode
= PIPE_READMODE_MESSAGE
| PIPE_WAIT
;
783 bError
= SetNamedPipeHandleState(hPipe
, &dwPipeMode
, NULL
, NULL
);
786 /* Couldn't change state, fail */
791 /* Do the transact */
792 bError
= TransactNamedPipe(hPipe
,
800 /* Close the handle */
812 DisconnectNamedPipe(HANDLE hNamedPipe
)
814 IO_STATUS_BLOCK Iosb
;
817 /* Send the FSCTL to the driver */
818 Status
= NtFsControlFile(hNamedPipe
,
823 FSCTL_PIPE_DISCONNECT
,
828 if (Status
== STATUS_PENDING
)
830 /* Wait on NPFS to finish and get updated status */
831 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
832 if (NT_SUCCESS(Status
))
833 Status
= Iosb
.Status
;
836 /* Check for error */
837 if (!NT_SUCCESS(Status
))
840 BaseSetLastNTError(Status
);
853 GetNamedPipeHandleStateW(HANDLE hNamedPipe
,
855 LPDWORD lpCurInstances
,
856 LPDWORD lpMaxCollectionCount
,
857 LPDWORD lpCollectDataTimeout
,
859 DWORD nMaxUserNameSize
)
861 IO_STATUS_BLOCK StatusBlock
;
866 FILE_PIPE_INFORMATION PipeInfo
;
868 Status
= NtQueryInformationFile(hNamedPipe
,
871 sizeof(FILE_PIPE_INFORMATION
),
872 FilePipeInformation
);
873 if (!NT_SUCCESS(Status
))
875 BaseSetLastNTError(Status
);
879 *lpState
= ((PipeInfo
.CompletionMode
!= FILE_PIPE_QUEUE_OPERATION
) ? PIPE_NOWAIT
: PIPE_WAIT
);
880 *lpState
|= ((PipeInfo
.ReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
) ? PIPE_READMODE_MESSAGE
: PIPE_READMODE_BYTE
);
883 if(lpCurInstances
!= NULL
)
885 FILE_PIPE_LOCAL_INFORMATION LocalInfo
;
887 Status
= NtQueryInformationFile(hNamedPipe
,
890 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
891 FilePipeLocalInformation
);
892 if (!NT_SUCCESS(Status
))
894 BaseSetLastNTError(Status
);
898 *lpCurInstances
= min(LocalInfo
.CurrentInstances
, PIPE_UNLIMITED_INSTANCES
);
901 if (lpMaxCollectionCount
!= NULL
|| lpCollectDataTimeout
!= NULL
)
903 FILE_PIPE_REMOTE_INFORMATION RemoteInfo
;
905 Status
= NtQueryInformationFile(hNamedPipe
,
908 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
909 FilePipeRemoteInformation
);
910 if (!NT_SUCCESS(Status
))
912 BaseSetLastNTError(Status
);
916 if (lpMaxCollectionCount
!= NULL
)
918 *lpMaxCollectionCount
= RemoteInfo
.MaximumCollectionCount
;
921 if(lpCollectDataTimeout
!= NULL
)
924 *lpCollectDataTimeout
= 0;
928 if (lpUserName
!= NULL
)
930 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
931 retreive the user name with GetUserName(), revert the impersonation
932 and finally restore the thread token */
944 GetNamedPipeHandleStateA(HANDLE hNamedPipe
,
946 LPDWORD lpCurInstances
,
947 LPDWORD lpMaxCollectionCount
,
948 LPDWORD lpCollectDataTimeout
,
950 DWORD nMaxUserNameSize
)
952 UNICODE_STRING UserNameW
= { 0, 0, NULL
};
953 ANSI_STRING UserNameA
;
956 if(lpUserName
!= NULL
)
958 UserNameW
.MaximumLength
= (USHORT
)nMaxUserNameSize
* sizeof(WCHAR
);
959 UserNameW
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW
.MaximumLength
);
960 if (UserNameW
.Buffer
== NULL
)
962 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
966 UserNameA
.Buffer
= lpUserName
;
967 UserNameA
.Length
= 0;
968 UserNameA
.MaximumLength
= (USHORT
)nMaxUserNameSize
;
971 Ret
= GetNamedPipeHandleStateW(hNamedPipe
,
974 lpMaxCollectionCount
,
975 lpCollectDataTimeout
,
978 if (Ret
&& lpUserName
!= NULL
)
982 RtlInitUnicodeString(&UserNameW
, UserNameW
.Buffer
);
983 Status
= RtlUnicodeStringToAnsiString(&UserNameA
, &UserNameW
, FALSE
);
984 if (!NT_SUCCESS(Status
))
986 BaseSetLastNTError(Status
);
991 if (UserNameW
.Buffer
!= NULL
)
993 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW
.Buffer
);
1005 GetNamedPipeInfo(HANDLE hNamedPipe
,
1007 LPDWORD lpOutBufferSize
,
1008 LPDWORD lpInBufferSize
,
1009 LPDWORD lpMaxInstances
)
1011 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation
;
1012 IO_STATUS_BLOCK StatusBlock
;
1015 Status
= NtQueryInformationFile(hNamedPipe
,
1017 &PipeLocalInformation
,
1018 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
1019 FilePipeLocalInformation
);
1020 if (!NT_SUCCESS(Status
))
1022 BaseSetLastNTError(Status
);
1026 if (lpFlags
!= NULL
)
1028 *lpFlags
= (PipeLocalInformation
.NamedPipeEnd
== FILE_PIPE_SERVER_END
) ? PIPE_SERVER_END
: PIPE_CLIENT_END
;
1029 *lpFlags
|= (PipeLocalInformation
.NamedPipeType
== 1) ? PIPE_TYPE_MESSAGE
: PIPE_TYPE_BYTE
;
1032 if (lpOutBufferSize
!= NULL
)
1033 *lpOutBufferSize
= PipeLocalInformation
.OutboundQuota
;
1035 if (lpInBufferSize
!= NULL
)
1036 *lpInBufferSize
= PipeLocalInformation
.InboundQuota
;
1038 if (lpMaxInstances
!= NULL
)
1040 if (PipeLocalInformation
.MaximumInstances
>= 255)
1041 *lpMaxInstances
= PIPE_UNLIMITED_INSTANCES
;
1043 *lpMaxInstances
= PipeLocalInformation
.MaximumInstances
;
1055 PeekNamedPipe(HANDLE hNamedPipe
,
1058 LPDWORD lpBytesRead
,
1059 LPDWORD lpTotalBytesAvail
,
1060 LPDWORD lpBytesLeftThisMessage
)
1062 PFILE_PIPE_PEEK_BUFFER Buffer
;
1063 IO_STATUS_BLOCK Iosb
;
1068 /* Calculate the buffer space that we'll need and allocate it */
1069 BufferSize
= nBufferSize
+ sizeof(FILE_PIPE_PEEK_BUFFER
);
1070 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
1073 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1077 /* Tell the driver to seek */
1078 Status
= NtFsControlFile(hNamedPipe
,
1088 if (Status
== STATUS_PENDING
)
1090 /* Wait for npfs to be done, and update the status */
1091 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
1092 if (NT_SUCCESS(Status
))
1093 Status
= Iosb
.Status
;
1096 /* Overflow is success for us */
1097 if (Status
== STATUS_BUFFER_OVERFLOW
)
1098 Status
= STATUS_SUCCESS
;
1101 if (!NT_SUCCESS(Status
))
1103 /* Free the buffer and return failure */
1104 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1105 BaseSetLastNTError(Status
);
1109 /* Check if caller requested bytes available */
1110 if (lpTotalBytesAvail
)
1111 *lpTotalBytesAvail
= Buffer
->ReadDataAvailable
;
1113 /* Calculate the bytes returned, minus our structure overhead */
1114 BytesRead
= (ULONG
)(Iosb
.Information
-
1115 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1117 /* Check if caller requested bytes read */
1120 /* Return the bytes read */
1121 *lpBytesRead
= BytesRead
;
1124 /* Check if caller requested bytes left */
1125 if (lpBytesLeftThisMessage
)
1127 /* Calculate total minus what we returned and our structure overhead */
1128 *lpBytesLeftThisMessage
= Buffer
->MessageLength
- BytesRead
;
1131 /* Check if the caller wanted to see the actual data */
1134 /* Give him what he wants */
1135 RtlCopyMemory(lpBuffer
,
1140 /* Free the buffer */
1141 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1152 TransactNamedPipe(IN HANDLE hNamedPipe
,
1153 IN LPVOID lpInBuffer
,
1154 IN DWORD nInBufferSize
,
1155 OUT LPVOID lpOutBuffer
,
1156 IN DWORD nOutBufferSize
,
1157 OUT LPDWORD lpBytesRead OPTIONAL
,
1158 IN LPOVERLAPPED lpOverlapped OPTIONAL
)
1162 if (lpBytesRead
!= NULL
)
1167 if (lpOverlapped
!= NULL
)
1171 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
1172 lpOverlapped
->Internal
= STATUS_PENDING
;
1174 Status
= NtFsControlFile(hNamedPipe
,
1175 lpOverlapped
->hEvent
,
1178 (PIO_STATUS_BLOCK
)lpOverlapped
,
1179 FSCTL_PIPE_TRANSCEIVE
,
1184 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1186 BaseSetLastNTError(Status
);
1190 if (lpBytesRead
!= NULL
)
1192 *lpBytesRead
= lpOverlapped
->InternalHigh
;
1197 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1198 IO_STATUS_BLOCK Iosb
;
1200 Status
= NtFsControlFile(hNamedPipe
,
1205 FSCTL_PIPE_TRANSCEIVE
,
1210 if (Status
== STATUS_PENDING
)
1212 Status
= NtWaitForSingleObject(hNamedPipe
,
1215 if (NT_SUCCESS(Status
))
1216 Status
= Iosb
.Status
;
1219 if (NT_SUCCESS(Status
))
1221 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1222 check that case either and crashes (only after the operation
1224 *lpBytesRead
= Iosb
.Information
;
1228 BaseSetLastNTError(Status
);
1231 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1234 while (0 != nInBufferSize
&&
1235 WriteFile(hNamedPipe
, lpInBuffer
, nInBufferSize
, &nActualBytes
,
1238 lpInBuffer
= (LPVOID
)((char *) lpInBuffer
+ nActualBytes
);
1239 nInBufferSize
-= nActualBytes
;
1242 if (0 != nInBufferSize
)
1244 /* Must have dropped out of the while 'cause WriteFile failed */
1248 if (!ReadFile(hNamedPipe
, lpOutBuffer
, nOutBufferSize
, &nActualBytes
,
1254 if (NULL
!= lpBytesRead
)
1256 *lpBytesRead
= nActualBytes
;