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 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
16 #include "../include/debug.h"
18 /* FUNCTIONS ****************************************************************/
25 CreateNamedPipeA(LPCSTR lpName
,
31 DWORD nDefaultTimeOut
,
32 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
34 PUNICODE_STRING NameU
= &NtCurrentTeb()->StaticUnicodeString
;
37 /* Initialize the string as ANSI_STRING and convert to Unicode */
38 RtlInitAnsiString(&NameA
, (LPSTR
)lpName
);
39 RtlAnsiStringToUnicodeString(NameU
, &NameA
, FALSE
);
41 /* Call the Unicode API */
42 return CreateNamedPipeW(NameU
->Buffer
,
49 lpSecurityAttributes
);
57 CreateNamedPipeW(LPCWSTR lpName
,
63 DWORD nDefaultTimeOut
,
64 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
66 UNICODE_STRING NamedPipeName
;
69 OBJECT_ATTRIBUTES ObjectAttributes
;
71 ACCESS_MASK DesiredAccess
;
72 ULONG CreateOptions
= 0;
73 ULONG WriteModeMessage
;
74 ULONG ReadModeMessage
;
77 ULONG ShareAccess
= 0, Attributes
;
78 LARGE_INTEGER DefaultTimeOut
;
79 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
81 /* Check for valid instances */
82 if (nMaxInstances
== 0 || nMaxInstances
> PIPE_UNLIMITED_INSTANCES
)
85 SetLastError(ERROR_INVALID_PARAMETER
);
86 return INVALID_HANDLE_VALUE
;
89 /* Convert to NT syntax */
90 if (nMaxInstances
== PIPE_UNLIMITED_INSTANCES
) nMaxInstances
= -1;
92 /* Convert the name */
93 Result
= RtlDosPathNameToNtPathName_U(lpName
,
99 /* Conversion failed */
100 SetLastError(ERROR_PATH_NOT_FOUND
);
101 return(INVALID_HANDLE_VALUE
);
104 DPRINT("Pipe name: %wZ\n", &NamedPipeName
);
105 DPRINT("Pipe name: %S\n", NamedPipeName
.Buffer
);
107 /* Always case insensitive, check if we got extra attributes */
108 Attributes
= OBJ_CASE_INSENSITIVE
;
109 if(lpSecurityAttributes
)
111 /* We did; get the security descriptor */
112 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
114 /* And check if this is pipe's handle will beinheritable */
115 if(lpSecurityAttributes
->bInheritHandle
) Attributes
|= OBJ_INHERIT
;
118 /* Now we can initialize the object attributes */
119 InitializeObjectAttributes(&ObjectAttributes
,
125 /* Setup the default Desired Access */
126 DesiredAccess
= SYNCHRONIZE
| (dwOpenMode
& (WRITE_DAC
|
128 ACCESS_SYSTEM_SECURITY
));
130 /* Convert to NT Create Flags */
131 if (dwOpenMode
& FILE_FLAG_WRITE_THROUGH
)
133 CreateOptions
|= FILE_WRITE_THROUGH
;
135 if (!(dwOpenMode
& FILE_FLAG_OVERLAPPED
))
137 CreateOptions
|= FILE_SYNCHRONOUS_IO_NONALERT
;
140 /* Handle all open modes */
141 if (dwOpenMode
& PIPE_ACCESS_OUTBOUND
)
143 ShareAccess
|= FILE_SHARE_READ
;
144 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 DPRINT1("NtCreateNamedPipe failed (Status %x)!\n", Status
);
227 SetLastErrorByStatus (Status
);
228 return INVALID_HANDLE_VALUE
;
231 /* Return the handle */
240 WaitNamedPipeA(LPCSTR lpNamedPipeName
,
244 UNICODE_STRING NameU
;
246 /* Convert the name to Unicode */
247 Basep8BitStringToLiveUnicodeString(&NameU
, lpNamedPipeName
);
249 /* Call the Unicode API */
250 r
= WaitNamedPipeW(NameU
.Buffer
, nTimeOut
);
252 /* Free the Unicode string */
253 RtlFreeUnicodeString(&NameU
);
260 * When NPFS will work properly, use this code instead. It is compatible with
261 * Microsoft's NPFS.SYS. The main difference is that:
262 * - This code actually respects the timeout instead of ignoring it!
263 * - This code validates and creates the proper names for both UNC and local pipes
264 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
265 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
266 * FILE_PIPE_WAIT_FOR_BUFFER structure.
268 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
274 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
277 UNICODE_STRING NamedPipeName
, NewName
, DevicePath
, PipePrefix
;
282 OBJECT_ATTRIBUTES ObjectAttributes
;
285 IO_STATUS_BLOCK IoStatusBlock
;
286 ULONG WaitPipeInfoSize
;
287 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo
;
289 /* Start by making a unicode string of the name */
290 DPRINT("Sent path: %S\n", lpNamedPipeName
);
291 RtlCreateUnicodeString(&NamedPipeName
, lpNamedPipeName
);
292 NameLength
= NamedPipeName
.Length
/ sizeof(WCHAR
);
294 /* All slashes must become backslashes */
295 for (i
= 0; i
< NameLength
; i
++)
297 /* Check and convert */
298 if (NamedPipeName
.Buffer
[i
] == L
'/') NamedPipeName
.Buffer
[i
] = L
'\\';
301 /* Find the path type of the name we were given */
302 NewName
= NamedPipeName
;
303 Type
= RtlDetermineDosPathNameType_U(lpNamedPipeName
);
305 /* Check if this was a device path, ie : "\\.\pipe\name" */
306 if (Type
== RtlPathTypeLocalDevice
)
308 /* Make sure it's a valid prefix */
309 RtlInitUnicodeString(&PipePrefix
, L
"\\\\.\\pipe\\");
310 RtlPrefixString((PANSI_STRING
)&PipePrefix
, (PANSI_STRING
)&NewName
, TRUE
);
314 NewName
.Length
-= 9 * sizeof(WCHAR
);
316 /* Initialize the Dos Devices name */
317 DPRINT("NewName: %wZ\n", &NewName
);
318 RtlInitUnicodeString(&DevicePath
, L
"\\DosDevices\\pipe\\");
320 else if (Type
== RtlPathTypeRootLocalDevice
)
322 /* The path is \\server\\pipe\name; find the pipename itself */
323 p
= &NewName
.Buffer
[2];
325 /* First loop to get past the server name */
328 /* Check if this is a backslash */
329 if (*p
== L
'\\') break;
335 /* Now make sure the full name contains "pipe\" */
336 if ((*p
) && !(_wcsnicmp(p
+ 1, L
"pipe\\", sizeof("pipe\\"))))
338 /* Get to the pipe name itself now */
339 p
+= sizeof("pipe\\") - 1;
343 /* The name is invalid */
344 DPRINT1("Invalid name!\n");
345 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD
);
349 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
353 DPRINT1("Invalid path type\n");
354 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD
);
358 /* Now calculate the total length of the structure and allocate it */
359 WaitPipeInfoSize
= FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER
, Name
[0]) +
361 WaitPipeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize
);
362 if (WaitPipeInfo
== NULL
)
364 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
368 /* Initialize the object attributes */
369 DPRINT("Opening: %wZ\n", &DevicePath
);
370 InitializeObjectAttributes(&ObjectAttributes
,
372 OBJ_CASE_INSENSITIVE
,
377 Status
= NtOpenFile(&FileHandle
,
378 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
381 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
382 FILE_SYNCHRONOUS_IO_NONALERT
);
383 if (!NT_SUCCESS(Status
))
385 /* Fail; couldn't open */
386 DPRINT1("Status: %lx\n", Status
);
387 SetLastErrorByStatus(Status
);
388 RtlFreeUnicodeString(&NamedPipeName
);
389 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
393 /* Check what timeout we got */
394 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
396 /* Don't use a timeout */
397 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
401 /* Check if we should wait forever */
402 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
405 WaitPipeInfo
->Timeout
.LowPart
= 0;
406 WaitPipeInfo
->Timeout
.HighPart
= 0x80000000;
410 /* Convert to NT format */
411 WaitPipeInfo
->Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
414 /* In both cases, we do have a timeout */
415 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
418 /* Set the length and copy the name */
419 WaitPipeInfo
->NameLength
= NewName
.Length
;
420 RtlCopyMemory(WaitPipeInfo
->Name
, NewName
.Buffer
, NewName
.Length
);
422 /* Get rid of the full name */
423 RtlFreeUnicodeString(&NamedPipeName
);
425 /* Let NPFS know of our request */
426 Status
= NtFsControlFile(FileHandle
,
437 /* Free our pipe info data and close the handle */
438 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
441 /* Check the status */
442 if (!NT_SUCCESS(Status
))
444 /* Failure to wait on the pipe */
445 DPRINT1("Status: %lx\n", Status
);
446 SetLastErrorByStatus (Status
);
458 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
461 UNICODE_STRING NamedPipeName
;
464 OBJECT_ATTRIBUTES ObjectAttributes
;
465 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
467 IO_STATUS_BLOCK Iosb
;
469 r
= RtlDosPathNameToNtPathName_U(lpNamedPipeName
,
478 InitializeObjectAttributes(&ObjectAttributes
,
480 OBJ_CASE_INSENSITIVE
,
483 Status
= NtOpenFile(&FileHandle
,
484 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
487 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
488 FILE_SYNCHRONOUS_IO_NONALERT
);
489 if (!NT_SUCCESS(Status
))
491 SetLastErrorByStatus (Status
);
495 WaitPipe
.Timeout
.QuadPart
= nTimeOut
* -10000LL;
497 Status
= NtFsControlFile(FileHandle
,
508 if (!NT_SUCCESS(Status
))
510 SetLastErrorByStatus (Status
);
522 ConnectNamedPipe(IN HANDLE hNamedPipe
,
523 IN LPOVERLAPPED lpOverlapped
)
527 if (lpOverlapped
!= NULL
)
531 lpOverlapped
->Internal
= STATUS_PENDING
;
532 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
534 Status
= NtFsControlFile(hNamedPipe
,
535 lpOverlapped
->hEvent
,
538 (PIO_STATUS_BLOCK
)lpOverlapped
,
545 /* return FALSE in case of failure and pending operations! */
546 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
548 SetLastErrorByStatus(Status
);
554 IO_STATUS_BLOCK Iosb
;
556 Status
= NtFsControlFile(hNamedPipe
,
567 /* wait in case operation is pending */
568 if (Status
== STATUS_PENDING
)
570 Status
= NtWaitForSingleObject(hNamedPipe
,
573 if (NT_SUCCESS(Status
))
575 Status
= Iosb
.Status
;
579 if (!NT_SUCCESS(Status
))
581 SetLastErrorByStatus(Status
);
594 SetNamedPipeHandleState(HANDLE hNamedPipe
,
596 LPDWORD lpMaxCollectionCount
,
597 LPDWORD lpCollectDataTimeout
)
599 IO_STATUS_BLOCK Iosb
;
602 /* Check if the Mode is being changed */
605 FILE_PIPE_INFORMATION Settings
;
607 /* Set the Completion Mode */
608 Settings
.CompletionMode
= (*lpMode
& PIPE_NOWAIT
) ?
609 FILE_PIPE_COMPLETE_OPERATION
: FILE_PIPE_QUEUE_OPERATION
;
611 /* Set the Read Mode */
612 Settings
.ReadMode
= (*lpMode
& PIPE_READMODE_MESSAGE
) ?
613 FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
615 /* Send the changes to the Driver */
616 Status
= NtSetInformationFile(hNamedPipe
,
619 sizeof(FILE_PIPE_INFORMATION
),
620 FilePipeInformation
);
621 if (!NT_SUCCESS(Status
))
623 SetLastErrorByStatus(Status
);
628 /* Check if the Collection count or Timeout are being changed */
629 if (lpMaxCollectionCount
|| lpCollectDataTimeout
)
631 FILE_PIPE_REMOTE_INFORMATION RemoteSettings
;
633 /* Setting one without the other would delete it, so we read old one */
634 if (!lpMaxCollectionCount
|| !lpCollectDataTimeout
)
636 Status
= NtQueryInformationFile(hNamedPipe
,
639 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
640 FilePipeRemoteInformation
);
642 if (!NT_SUCCESS(Status
))
644 SetLastErrorByStatus(Status
);
649 /* Now set the new settings */
650 RemoteSettings
.MaximumCollectionCount
= (lpMaxCollectionCount
) ?
651 *lpMaxCollectionCount
:
652 RemoteSettings
.MaximumCollectionCount
;
653 if (lpCollectDataTimeout
)
655 /* Convert it to Quad */
656 RemoteSettings
.CollectDataTime
.QuadPart
= -(LONGLONG
)
658 *lpCollectDataTimeout
);
661 /* Tell the driver to change them */
662 Status
= NtSetInformationFile(hNamedPipe
,
665 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
666 FilePipeRemoteInformation
);
668 if (!NT_SUCCESS(Status
))
670 SetLastErrorByStatus(Status
);
684 CallNamedPipeA(LPCSTR lpNamedPipeName
,
688 DWORD nOutBufferSize
,
692 PUNICODE_STRING PipeName
= &NtCurrentTeb()->StaticUnicodeString
;
693 ANSI_STRING AnsiPipe
;
695 /* Initialize the string as ANSI_STRING and convert to Unicode */
696 RtlInitAnsiString(&AnsiPipe
, (LPSTR
)lpNamedPipeName
);
697 RtlAnsiStringToUnicodeString(PipeName
, &AnsiPipe
, FALSE
);
699 /* Call the Unicode function */
700 return CallNamedPipeW(PipeName
->Buffer
,
714 CallNamedPipeW(LPCWSTR lpNamedPipeName
,
718 DWORD nOutBufferSize
,
729 /* Try creating it */
730 hPipe
= CreateFileW(lpNamedPipeName
,
731 GENERIC_READ
| GENERIC_WRITE
,
732 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
735 FILE_ATTRIBUTE_NORMAL
,
738 /* Success, break out */
739 if (hPipe
!= INVALID_HANDLE_VALUE
) break;
741 /* Already tried twice, give up */
742 if (bRetry
== FALSE
) return FALSE
;
745 WaitNamedPipeW(lpNamedPipeName
, nTimeOut
);
747 /* Get ready to try again */
751 /* Set the pipe mode */
752 dwPipeMode
= PIPE_READMODE_MESSAGE
| PIPE_WAIT
;
753 bError
= SetNamedPipeHandleState(hPipe
, &dwPipeMode
, NULL
, NULL
);
756 /* Couldn't change state, fail */
761 /* Do the transact */
762 bError
= TransactNamedPipe(hPipe
,
770 /* Close the handle and return */
780 DisconnectNamedPipe(HANDLE hNamedPipe
)
782 IO_STATUS_BLOCK Iosb
;
785 /* Send the FSCTL to the driver */
786 Status
= NtFsControlFile(hNamedPipe
,
791 FSCTL_PIPE_DISCONNECT
,
796 if (Status
== STATUS_PENDING
)
798 /* Wait on NPFS to finish and get updated status */
799 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
800 if (NT_SUCCESS(Status
)) Status
= Iosb
.Status
;
803 /* Check for error */
804 if (!NT_SUCCESS(Status
))
807 SetLastErrorByStatus(Status
);
818 GetNamedPipeHandleStateW(HANDLE hNamedPipe
,
820 LPDWORD lpCurInstances
,
821 LPDWORD lpMaxCollectionCount
,
822 LPDWORD lpCollectDataTimeout
,
824 DWORD nMaxUserNameSize
)
826 IO_STATUS_BLOCK StatusBlock
;
831 FILE_PIPE_INFORMATION PipeInfo
;
833 Status
= NtQueryInformationFile(hNamedPipe
,
836 sizeof(FILE_PIPE_INFORMATION
),
837 FilePipeInformation
);
838 if (!NT_SUCCESS(Status
))
840 SetLastErrorByStatus(Status
);
844 *lpState
= ((PipeInfo
.CompletionMode
!= FILE_PIPE_QUEUE_OPERATION
) ? PIPE_NOWAIT
: PIPE_WAIT
);
845 *lpState
|= ((PipeInfo
.ReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
) ? PIPE_READMODE_MESSAGE
: PIPE_READMODE_BYTE
);
848 if(lpCurInstances
!= NULL
)
850 FILE_PIPE_LOCAL_INFORMATION LocalInfo
;
852 Status
= NtQueryInformationFile(hNamedPipe
,
855 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
856 FilePipeLocalInformation
);
857 if(!NT_SUCCESS(Status
))
859 SetLastErrorByStatus(Status
);
863 *lpCurInstances
= min(LocalInfo
.CurrentInstances
, PIPE_UNLIMITED_INSTANCES
);
866 if(lpMaxCollectionCount
!= NULL
|| lpCollectDataTimeout
!= NULL
)
868 FILE_PIPE_REMOTE_INFORMATION RemoteInfo
;
870 Status
= NtQueryInformationFile(hNamedPipe
,
873 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
874 FilePipeRemoteInformation
);
875 if(!NT_SUCCESS(Status
))
877 SetLastErrorByStatus(Status
);
881 if(lpMaxCollectionCount
!= NULL
)
883 *lpMaxCollectionCount
= RemoteInfo
.MaximumCollectionCount
;
886 if(lpCollectDataTimeout
!= NULL
)
889 *lpCollectDataTimeout
= 0;
893 if(lpUserName
!= NULL
)
895 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
896 retreive the user name with GetUserName(), revert the impersonation
897 and finally restore the thread token */
908 GetNamedPipeHandleStateA(HANDLE hNamedPipe
,
910 LPDWORD lpCurInstances
,
911 LPDWORD lpMaxCollectionCount
,
912 LPDWORD lpCollectDataTimeout
,
914 DWORD nMaxUserNameSize
)
916 UNICODE_STRING UserNameW
= {0};
917 ANSI_STRING UserNameA
;
920 if(lpUserName
!= NULL
)
922 UserNameW
.MaximumLength
= (USHORT
)nMaxUserNameSize
* sizeof(WCHAR
);
923 UserNameW
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW
.MaximumLength
);
924 if (UserNameW
.Buffer
== NULL
)
926 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
930 UserNameA
.Buffer
= lpUserName
;
931 UserNameA
.Length
= 0;
932 UserNameA
.MaximumLength
= (USHORT
)nMaxUserNameSize
;
935 Ret
= GetNamedPipeHandleStateW(hNamedPipe
,
938 lpMaxCollectionCount
,
939 lpCollectDataTimeout
,
943 if(Ret
&& lpUserName
!= NULL
)
947 RtlInitUnicodeString(&UserNameW
, UserNameW
.Buffer
);
948 Status
= RtlUnicodeStringToAnsiString(&UserNameA
, &UserNameW
, FALSE
);
949 if(!NT_SUCCESS(Status
))
951 SetLastErrorByStatus(Status
);
956 if(UserNameW
.Buffer
!= NULL
)
958 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW
.Buffer
);
969 GetNamedPipeInfo(HANDLE hNamedPipe
,
971 LPDWORD lpOutBufferSize
,
972 LPDWORD lpInBufferSize
,
973 LPDWORD lpMaxInstances
)
975 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation
;
976 IO_STATUS_BLOCK StatusBlock
;
979 Status
= NtQueryInformationFile(hNamedPipe
,
981 &PipeLocalInformation
,
982 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
983 FilePipeLocalInformation
);
984 if (!NT_SUCCESS(Status
))
986 SetLastErrorByStatus(Status
);
992 *lpFlags
= (PipeLocalInformation
.NamedPipeEnd
== FILE_PIPE_SERVER_END
) ? PIPE_SERVER_END
: PIPE_CLIENT_END
;
993 *lpFlags
|= (PipeLocalInformation
.NamedPipeType
== 1) ? PIPE_TYPE_MESSAGE
: PIPE_TYPE_BYTE
;
996 if (lpOutBufferSize
!= NULL
)
997 *lpOutBufferSize
= PipeLocalInformation
.OutboundQuota
;
999 if (lpInBufferSize
!= NULL
)
1000 *lpInBufferSize
= PipeLocalInformation
.InboundQuota
;
1002 if (lpMaxInstances
!= NULL
)
1004 if (PipeLocalInformation
.MaximumInstances
>= 255)
1005 *lpMaxInstances
= PIPE_UNLIMITED_INSTANCES
;
1007 *lpMaxInstances
= PipeLocalInformation
.MaximumInstances
;
1018 PeekNamedPipe(HANDLE hNamedPipe
,
1021 LPDWORD lpBytesRead
,
1022 LPDWORD lpTotalBytesAvail
,
1023 LPDWORD lpBytesLeftThisMessage
)
1025 PFILE_PIPE_PEEK_BUFFER Buffer
;
1026 IO_STATUS_BLOCK Iosb
;
1030 /* Calculate the buffer space that we'll need and allocate it */
1031 BufferSize
= nBufferSize
+ FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]);
1032 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
1035 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1039 /* Tell the driver to seek */
1040 Status
= NtFsControlFile(hNamedPipe
,
1050 if (Status
== STATUS_PENDING
)
1052 /* Wait for npfs to be done, and update the status */
1053 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
1054 if (NT_SUCCESS(Status
)) Status
= Iosb
.Status
;
1057 /* Overflow is success for us */
1058 if (Status
== STATUS_BUFFER_OVERFLOW
) Status
= STATUS_SUCCESS
;
1061 if (!NT_SUCCESS(Status
))
1063 /* Free the buffer and return failure */
1064 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1065 SetLastErrorByStatus(Status
);
1069 /* Check if caller requested bytes available */
1070 if (lpTotalBytesAvail
) *lpTotalBytesAvail
= Buffer
->ReadDataAvailable
;
1072 /* Check if caller requested bytes read */
1075 /* Calculate the bytes returned, minus our structure overhead */
1076 *lpBytesRead
= (ULONG
)(Iosb
.Information
-
1077 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1080 /* Check if caller requested bytes left */
1081 if (lpBytesLeftThisMessage
)
1083 /* Calculate total minus what we returned and our structure overhead */
1084 *lpBytesLeftThisMessage
= Buffer
->MessageLength
-
1085 (ULONG
)(Iosb
.Information
-
1086 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1089 /* Check if the caller wanted to see the actual data */
1092 /* Give him what he wants */
1093 RtlCopyMemory(lpBuffer
,
1096 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1099 /* Free the buffer and return success */
1100 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1108 TransactNamedPipe(IN HANDLE hNamedPipe
,
1109 IN LPVOID lpInBuffer
,
1110 IN DWORD nInBufferSize
,
1111 OUT LPVOID lpOutBuffer
,
1112 IN DWORD nOutBufferSize
,
1113 OUT LPDWORD lpBytesRead OPTIONAL
,
1114 IN LPOVERLAPPED lpOverlapped OPTIONAL
)
1118 if (lpBytesRead
!= NULL
)
1123 if (lpOverlapped
!= NULL
)
1127 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
1128 lpOverlapped
->Internal
= STATUS_PENDING
;
1130 Status
= NtFsControlFile(hNamedPipe
,
1131 lpOverlapped
->hEvent
,
1134 (PIO_STATUS_BLOCK
)lpOverlapped
,
1135 FSCTL_PIPE_TRANSCEIVE
,
1141 /* return FALSE in case of failure and pending operations! */
1142 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1144 SetLastErrorByStatus(Status
);
1148 if (lpBytesRead
!= NULL
)
1150 *lpBytesRead
= lpOverlapped
->InternalHigh
;
1155 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1156 IO_STATUS_BLOCK Iosb
;
1158 Status
= NtFsControlFile(hNamedPipe
,
1163 FSCTL_PIPE_TRANSCEIVE
,
1169 /* wait in case operation is pending */
1170 if (Status
== STATUS_PENDING
)
1172 Status
= NtWaitForSingleObject(hNamedPipe
,
1175 if (NT_SUCCESS(Status
))
1177 Status
= Iosb
.Status
;
1181 if (NT_SUCCESS(Status
))
1183 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1184 check that case either and crashes (only after the operation
1186 *lpBytesRead
= Iosb
.Information
;
1190 SetLastErrorByStatus(Status
);
1193 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1196 while (0 != nInBufferSize
&&
1197 WriteFile(hNamedPipe
, lpInBuffer
, nInBufferSize
, &nActualBytes
,
1200 lpInBuffer
= (LPVOID
)((char *) lpInBuffer
+ nActualBytes
);
1201 nInBufferSize
-= nActualBytes
;
1203 if (0 != nInBufferSize
)
1205 /* Must have dropped out of the while 'cause WriteFile failed */
1208 if (! ReadFile(hNamedPipe
, lpOutBuffer
, nOutBufferSize
, &nActualBytes
,
1213 if (NULL
!= lpBytesRead
)
1215 *lpBytesRead
= nActualBytes
;