- Optimize CallNamedPipeA too and remove accidental define.
[reactos.git] / reactos / lib / kernel32 / file / npipe.c
1 /*
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)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <k32.h>
13
14 #define NDEBUG
15 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
16 #include "../include/debug.h"
17
18 /* FUNCTIONS ****************************************************************/
19
20 /*
21 * @implemented
22 */
23 HANDLE
24 WINAPI
25 CreateNamedPipeA(LPCSTR lpName,
26 DWORD dwOpenMode,
27 DWORD dwPipeMode,
28 DWORD nMaxInstances,
29 DWORD nOutBufferSize,
30 DWORD nInBufferSize,
31 DWORD nDefaultTimeOut,
32 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
33 {
34 PUNICODE_STRING NameU = &NtCurrentTeb()->StaticUnicodeString;
35 ANSI_STRING NameA;
36
37 /* Initialize the string as ANSI_STRING and convert to Unicode */
38 RtlInitAnsiString(&NameA, (LPSTR)lpName);
39 RtlAnsiStringToUnicodeString(NameU, &NameA, FALSE);
40
41 /* Call the Unicode API */
42 return CreateNamedPipeW(NameU->Buffer,
43 dwOpenMode,
44 dwPipeMode,
45 nMaxInstances,
46 nOutBufferSize,
47 nInBufferSize,
48 nDefaultTimeOut,
49 lpSecurityAttributes);
50 }
51
52 /*
53 * @implemented
54 */
55 HANDLE
56 STDCALL
57 CreateNamedPipeW(LPCWSTR lpName,
58 DWORD dwOpenMode,
59 DWORD dwPipeMode,
60 DWORD nMaxInstances,
61 DWORD nOutBufferSize,
62 DWORD nInBufferSize,
63 DWORD nDefaultTimeOut,
64 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
65 {
66 UNICODE_STRING NamedPipeName;
67 BOOL Result;
68 NTSTATUS Status;
69 OBJECT_ATTRIBUTES ObjectAttributes;
70 HANDLE PipeHandle;
71 ACCESS_MASK DesiredAccess;
72 ULONG CreateOptions = 0;
73 ULONG WriteModeMessage;
74 ULONG ReadModeMessage;
75 ULONG NonBlocking;
76 IO_STATUS_BLOCK Iosb;
77 ULONG ShareAccess = 0, Attributes;
78 LARGE_INTEGER DefaultTimeOut;
79 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
80
81 /* Check for valid instances */
82 if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
83 {
84 /* Fail */
85 SetLastError(ERROR_INVALID_PARAMETER);
86 return INVALID_HANDLE_VALUE;
87 }
88
89 /* Convert to NT syntax */
90 if (nMaxInstances == PIPE_UNLIMITED_INSTANCES) nMaxInstances = -1;
91
92 /* Convert the name */
93 Result = RtlDosPathNameToNtPathName_U((LPWSTR)lpName,
94 &NamedPipeName,
95 NULL,
96 NULL);
97 if (!Result)
98 {
99 /* Conversion failed */
100 SetLastError(ERROR_PATH_NOT_FOUND);
101 return(INVALID_HANDLE_VALUE);
102 }
103
104 DPRINT("Pipe name: %wZ\n", &NamedPipeName);
105 DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
106
107 /* Always case insensitive, check if we got extra attributes */
108 Attributes = OBJ_CASE_INSENSITIVE;
109 if(lpSecurityAttributes)
110 {
111 /* We did; get the security descriptor */
112 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
113
114 /* And check if this is pipe's handle will beinheritable */
115 if(lpSecurityAttributes->bInheritHandle) Attributes |= OBJ_INHERIT;
116 }
117
118 /* Now we can initialize the object attributes */
119 InitializeObjectAttributes(&ObjectAttributes,
120 &NamedPipeName,
121 Attributes,
122 NULL,
123 SecurityDescriptor);
124
125 /* Setup the default Desired Access */
126 DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC |
127 WRITE_OWNER |
128 ACCESS_SYSTEM_SECURITY));
129
130 /* Convert to NT Create Flags */
131 if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
132 {
133 CreateOptions |= FILE_WRITE_THROUGH;
134 }
135 if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
136 {
137 CreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
138 }
139
140 /* Handle all open modes */
141 if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
142 {
143 ShareAccess |= FILE_SHARE_READ;
144 DesiredAccess |= GENERIC_WRITE;
145 }
146 if (dwOpenMode & PIPE_ACCESS_INBOUND)
147 {
148 ShareAccess |= FILE_SHARE_WRITE;
149 DesiredAccess |= GENERIC_READ;
150 }
151
152 /* Handle the type flags */
153 if (dwPipeMode & PIPE_TYPE_MESSAGE)
154 {
155 WriteModeMessage = FILE_PIPE_MESSAGE_TYPE;
156 }
157 else
158 {
159 WriteModeMessage = FILE_PIPE_BYTE_STREAM_TYPE;
160 }
161
162 /* Handle the mode flags */
163 if (dwPipeMode & PIPE_READMODE_MESSAGE)
164 {
165 ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
166 }
167 else
168 {
169 ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
170 }
171
172 /* Handle the blocking mode */
173 if (dwPipeMode & PIPE_NOWAIT)
174 {
175 NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
176 }
177 else
178 {
179 NonBlocking = FILE_PIPE_QUEUE_OPERATION;
180 }
181
182 /* Check if we have a timeout */
183 if (nDefaultTimeOut)
184 {
185 /* Convert the time to NT format */
186 DefaultTimeOut.QuadPart = UInt32x32To64(nDefaultTimeOut, -10000);
187 }
188 else
189 {
190 /* Use default timeout of 50 ms */
191 DefaultTimeOut.QuadPart = -500000;
192 }
193
194 /* Now create the pipe */
195 Status = NtCreateNamedPipeFile(&PipeHandle,
196 DesiredAccess,
197 &ObjectAttributes,
198 &Iosb,
199 ShareAccess,
200 FILE_OPEN_IF,
201 CreateOptions,
202 WriteModeMessage,
203 ReadModeMessage,
204 NonBlocking,
205 nMaxInstances,
206 nInBufferSize,
207 nOutBufferSize,
208 &DefaultTimeOut);
209
210 /* Free the name */
211 RtlFreeUnicodeString(&NamedPipeName);
212
213 /* Check status */
214 if (!NT_SUCCESS(Status))
215 {
216 /* Failed to create it */
217 DPRINT1("NtCreateNamedPipe failed (Status %x)!\n", Status);
218 SetLastErrorByStatus (Status);
219 return INVALID_HANDLE_VALUE;
220 }
221
222 /* Return the handle */
223 return PipeHandle;
224 }
225
226 /*
227 * @implemented
228 */
229 BOOL
230 WINAPI
231 WaitNamedPipeA(LPCSTR lpNamedPipeName,
232 DWORD nTimeOut)
233 {
234 BOOL r;
235 UNICODE_STRING NameU;
236
237 /* Convert the name to Unicode */
238 Basep8BitStringToLiveUnicodeString(&NameU, lpNamedPipeName);
239
240 /* Call the Unicode API */
241 r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
242
243 /* Free the Unicode string */
244 RtlFreeUnicodeString(&NameU);
245
246 /* Return result */
247 return r;
248 }
249
250 /*
251 * When NPFS will work properly, use this code instead. It is compatible with
252 * Microsoft's NPFS.SYS. The main difference is that:
253 * - This code actually respects the timeout instead of ignoring it!
254 * - This code validates and creates the proper names for both UNC and local pipes
255 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
256 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
257 * FILE_PIPE_WAIT_FOR_BUFFER structure.
258 */
259 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
260 /*
261 * @implemented
262 */
263 BOOL
264 WINAPI
265 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
266 DWORD nTimeOut)
267 {
268 UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix;
269 ULONG NameLength;
270 ULONG i;
271 PWCHAR p;
272 ULONG Type;
273 OBJECT_ATTRIBUTES ObjectAttributes;
274 NTSTATUS Status;
275 HANDLE FileHandle;
276 IO_STATUS_BLOCK IoStatusBlock;
277 ULONG WaitPipeInfoSize;
278 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;
279
280 /* Start by making a unicode string of the name */
281 DPRINT("Sent path: %S\n", lpNamedPipeName);
282 RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName);
283 NameLength = NamedPipeName.Length / sizeof(WCHAR);
284
285 /* All slashes must become backslashes */
286 for (i = 0; i < NameLength; i++)
287 {
288 /* Check and convert */
289 if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
290 }
291
292 /* Find the path type of the name we were given */
293 NewName = NamedPipeName;
294 Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);
295
296 /* Check if this was a device path, ie : "\\.\pipe\name" */
297 if (Type == DEVICE_PATH)
298 {
299 /* Make sure it's a valid prefix */
300 RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
301 RtlPrefixString((PANSI_STRING)&PipePrefix, (PANSI_STRING)&NewName, TRUE);
302
303 /* Move past it */
304 NewName.Buffer += 9;
305 NewName.Length -= 9 * sizeof(WCHAR);
306
307 /* Initialize the Dos Devices name */
308 DPRINT("NewName: %wZ\n", &NewName);
309 RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
310 }
311 else if (Type == UNC_PATH)
312 {
313 /* The path is \\server\\pipe\name; find the pipename itself */
314 p = &NewName.Buffer[2];
315
316 /* First loop to get past the server name */
317 do
318 {
319 /* Check if this is a backslash */
320 if (*p == L'\\') break;
321
322 /* Check next */
323 p++;
324 } while (*p);
325
326 /* Now make sure the full name contains "pipe\" */
327 if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\"))))
328 {
329 /* Get to the pipe name itself now */
330 p += sizeof("pipe\\") - 1;
331 }
332 else
333 {
334 /* The name is invalid */
335 DPRINT1("Invalid name!\n");
336 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD);
337 return FALSE;
338 }
339
340 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
341 }
342 else
343 {
344 DPRINT1("Invalid path type\n");
345 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD);
346 return FALSE;
347 }
348
349 /* Initialize the object attributes */
350 DPRINT("Opening: %wZ\n", &DevicePath);
351 InitializeObjectAttributes(&ObjectAttributes,
352 &DevicePath,
353 OBJ_CASE_INSENSITIVE,
354 NULL,
355 NULL);
356
357 /* Open the path */
358 Status = NtOpenFile(&FileHandle,
359 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
360 &ObjectAttributes,
361 &IoStatusBlock,
362 FILE_SHARE_READ | FILE_SHARE_WRITE,
363 FILE_SYNCHRONOUS_IO_NONALERT);
364 if (!NT_SUCCESS(Status))
365 {
366 /* Fail; couldn't open */
367 DPRINT1("Status: %lx\n", Status);
368 SetLastErrorByStatus(Status);
369 RtlFreeUnicodeString(&NamedPipeName);
370 return(FALSE);
371 }
372
373 /* Now calculate the total length of the structure and allocate it */
374 WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
375 NewName.Length;
376 WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
377
378 /* Check what timeout we got */
379 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
380 {
381 /* Don't use a timeout */
382 WaitPipeInfo->TimeoutSpecified = FALSE;
383 }
384 else
385 {
386 /* Check if we should wait forever */
387 if (nTimeOut == NMPWAIT_WAIT_FOREVER)
388 {
389 /* Set the max */
390 WaitPipeInfo->Timeout.LowPart = 0;
391 WaitPipeInfo->Timeout.HighPart = 0x80000000;
392 }
393 else
394 {
395 /* Convert to NT format */
396 WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut);
397 }
398
399 /* In both cases, we do have a timeout */
400 WaitPipeInfo->TimeoutSpecified = FALSE;
401 }
402
403 /* Set the length and copy the name */
404 WaitPipeInfo->NameLength = NewName.Length;
405 RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);
406
407 /* Get rid of the full name */
408 RtlFreeUnicodeString(&NamedPipeName);
409
410 /* Let NPFS know of our request */
411 Status = NtFsControlFile(FileHandle,
412 NULL,
413 NULL,
414 NULL,
415 &IoStatusBlock,
416 FSCTL_PIPE_WAIT,
417 WaitPipeInfo,
418 WaitPipeInfoSize,
419 NULL,
420 0);
421
422 /* Free our pipe info data and close the handle */
423 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
424 NtClose(FileHandle);
425
426 /* Check the status */
427 if (!NT_SUCCESS(Status))
428 {
429 /* Failure to wait on the pipe */
430 DPRINT1("Status: %lx\n", Status);
431 SetLastErrorByStatus (Status);
432 return FALSE;
433 }
434
435 /* Success */
436 return TRUE;
437 }
438 #else
439 /*
440 * @implemented
441 */
442 BOOL STDCALL
443 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
444 DWORD nTimeOut)
445 {
446 UNICODE_STRING NamedPipeName;
447 BOOL r;
448 NTSTATUS Status;
449 OBJECT_ATTRIBUTES ObjectAttributes;
450 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
451 HANDLE FileHandle;
452 IO_STATUS_BLOCK Iosb;
453
454 r = RtlDosPathNameToNtPathName_U((LPWSTR)lpNamedPipeName,
455 &NamedPipeName,
456 NULL,
457 NULL);
458 if (!r)
459 {
460 return(FALSE);
461 }
462
463 InitializeObjectAttributes(&ObjectAttributes,
464 &NamedPipeName,
465 OBJ_CASE_INSENSITIVE,
466 NULL,
467 NULL);
468 Status = NtOpenFile(&FileHandle,
469 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
470 &ObjectAttributes,
471 &Iosb,
472 FILE_SHARE_READ | FILE_SHARE_WRITE,
473 FILE_SYNCHRONOUS_IO_NONALERT);
474 if (!NT_SUCCESS(Status))
475 {
476 SetLastErrorByStatus (Status);
477 return(FALSE);
478 }
479
480 WaitPipe.Timeout.QuadPart = nTimeOut * -10000LL;
481
482 Status = NtFsControlFile(FileHandle,
483 NULL,
484 NULL,
485 NULL,
486 &Iosb,
487 FSCTL_PIPE_WAIT,
488 &WaitPipe,
489 sizeof(WaitPipe),
490 NULL,
491 0);
492 NtClose(FileHandle);
493 if (!NT_SUCCESS(Status))
494 {
495 SetLastErrorByStatus (Status);
496 return(FALSE);
497 }
498
499 return(TRUE);
500 }
501 #endif
502
503 /*
504 * @implemented
505 */
506 BOOL STDCALL
507 ConnectNamedPipe(IN HANDLE hNamedPipe,
508 IN LPOVERLAPPED lpOverlapped)
509 {
510 NTSTATUS Status;
511
512 if (lpOverlapped != NULL)
513 {
514 PVOID ApcContext;
515
516 lpOverlapped->Internal = STATUS_PENDING;
517 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
518
519 Status = NtFsControlFile(hNamedPipe,
520 lpOverlapped->hEvent,
521 NULL,
522 ApcContext,
523 (PIO_STATUS_BLOCK)lpOverlapped,
524 FSCTL_PIPE_LISTEN,
525 NULL,
526 0,
527 NULL,
528 0);
529
530 /* return FALSE in case of failure and pending operations! */
531 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
532 {
533 SetLastErrorByStatus(Status);
534 return FALSE;
535 }
536 }
537 else
538 {
539 IO_STATUS_BLOCK Iosb;
540
541 Status = NtFsControlFile(hNamedPipe,
542 NULL,
543 NULL,
544 NULL,
545 &Iosb,
546 FSCTL_PIPE_LISTEN,
547 NULL,
548 0,
549 NULL,
550 0);
551
552 /* wait in case operation is pending */
553 if (Status == STATUS_PENDING)
554 {
555 Status = NtWaitForSingleObject(hNamedPipe,
556 FALSE,
557 NULL);
558 if (NT_SUCCESS(Status))
559 {
560 Status = Iosb.Status;
561 }
562 }
563
564 if (!NT_SUCCESS(Status))
565 {
566 SetLastErrorByStatus(Status);
567 return FALSE;
568 }
569 }
570
571 return TRUE;
572 }
573
574 /*
575 * @implemented
576 */
577 BOOL
578 STDCALL
579 SetNamedPipeHandleState(HANDLE hNamedPipe,
580 LPDWORD lpMode,
581 LPDWORD lpMaxCollectionCount,
582 LPDWORD lpCollectDataTimeout)
583 {
584 IO_STATUS_BLOCK Iosb;
585 NTSTATUS Status;
586
587 /* Check if the Mode is being changed */
588 if (lpMode)
589 {
590 FILE_PIPE_INFORMATION Settings;
591
592 /* Set the Completion Mode */
593 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
594 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
595
596 /* Set the Read Mode */
597 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
598 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
599
600 /* Send the changes to the Driver */
601 Status = NtSetInformationFile(hNamedPipe,
602 &Iosb,
603 &Settings,
604 sizeof(FILE_PIPE_INFORMATION),
605 FilePipeInformation);
606 if (!NT_SUCCESS(Status))
607 {
608 SetLastErrorByStatus(Status);
609 return(FALSE);
610 }
611 }
612
613 /* Check if the Collection count or Timeout are being changed */
614 if (lpMaxCollectionCount || lpCollectDataTimeout)
615 {
616 FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
617
618 /* Setting one without the other would delete it, so we read old one */
619 if (!lpMaxCollectionCount || !lpCollectDataTimeout)
620 {
621 Status = NtQueryInformationFile(hNamedPipe,
622 &Iosb,
623 &RemoteSettings,
624 sizeof(FILE_PIPE_REMOTE_INFORMATION),
625 FilePipeRemoteInformation);
626
627 if (!NT_SUCCESS(Status))
628 {
629 SetLastErrorByStatus(Status);
630 return(FALSE);
631 }
632 }
633
634 /* Now set the new settings */
635 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
636 *lpMaxCollectionCount :
637 RemoteSettings.MaximumCollectionCount;
638 if (lpCollectDataTimeout)
639 {
640 /* Convert it to Quad */
641 RemoteSettings.CollectDataTime.QuadPart = -(LONGLONG)
642 UInt32x32To64(10000,
643 *lpCollectDataTimeout);
644 }
645
646 /* Tell the driver to change them */
647 Status = NtSetInformationFile(hNamedPipe,
648 &Iosb,
649 &RemoteSettings,
650 sizeof(FILE_PIPE_REMOTE_INFORMATION),
651 FilePipeRemoteInformation);
652
653 if (!NT_SUCCESS(Status))
654 {
655 SetLastErrorByStatus(Status);
656 return(FALSE);
657 }
658 }
659
660 /* All done */
661 return TRUE;
662 }
663
664 /*
665 * @implemented
666 */
667 BOOL
668 WINAPI
669 CallNamedPipeA(LPCSTR lpNamedPipeName,
670 LPVOID lpInBuffer,
671 DWORD nInBufferSize,
672 LPVOID lpOutBuffer,
673 DWORD nOutBufferSize,
674 LPDWORD lpBytesRead,
675 DWORD nTimeOut)
676 {
677 UNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
678 ANSI_STRING AnsiPipe;
679
680 /* Initialize the string as ANSI_STRING and convert to Unicode */
681 RtlInitAnsiString(&NameA, (LPSTR)lpName);
682 RtlAnsiStringToUnicodeString(NameU, &NameA, FALSE);
683
684 /* Call the Unicode function */
685 return CallNamedPipeW(PipeName->Buffer,
686 lpInBuffer,
687 nInBufferSize,
688 lpOutBuffer,
689 nOutBufferSize,
690 lpBytesRead,
691 nTimeOut);
692 }
693
694 /*
695 * @implemented
696 */
697 BOOL STDCALL
698 CallNamedPipeW(LPCWSTR lpNamedPipeName,
699 LPVOID lpInBuffer,
700 DWORD nInBufferSize,
701 LPVOID lpOutBuffer,
702 DWORD nOutBufferSize,
703 LPDWORD lpBytesRead,
704 DWORD nTimeOut)
705 {
706 HANDLE hPipe = INVALID_HANDLE_VALUE;
707 BOOL bRetry = TRUE;
708 BOOL bError = FALSE;
709 DWORD dwPipeMode;
710
711 while (TRUE)
712 {
713 hPipe = CreateFileW(lpNamedPipeName,
714 GENERIC_READ | GENERIC_WRITE,
715 FILE_SHARE_READ | FILE_SHARE_WRITE,
716 NULL,
717 OPEN_EXISTING,
718 FILE_ATTRIBUTE_NORMAL,
719 NULL);
720 if (hPipe != INVALID_HANDLE_VALUE)
721 break;
722
723 if (bRetry == FALSE)
724 return(FALSE);
725
726 WaitNamedPipeW(lpNamedPipeName,
727 nTimeOut);
728
729 bRetry = FALSE;
730 }
731
732 dwPipeMode = PIPE_READMODE_MESSAGE;
733 bError = SetNamedPipeHandleState(hPipe,
734 &dwPipeMode,
735 NULL,
736 NULL);
737 if (!bError)
738 {
739 CloseHandle(hPipe);
740 return(FALSE);
741 }
742
743 bError = TransactNamedPipe(hPipe,
744 lpInBuffer,
745 nInBufferSize,
746 lpOutBuffer,
747 nOutBufferSize,
748 lpBytesRead,
749 NULL);
750 CloseHandle(hPipe);
751
752 return(bError);
753 }
754
755
756 /*
757 * @implemented
758 */
759 BOOL STDCALL
760 DisconnectNamedPipe(HANDLE hNamedPipe)
761 {
762 IO_STATUS_BLOCK Iosb;
763 NTSTATUS Status;
764
765 Status = NtFsControlFile(hNamedPipe,
766 NULL,
767 NULL,
768 NULL,
769 &Iosb,
770 FSCTL_PIPE_DISCONNECT,
771 NULL,
772 0,
773 NULL,
774 0);
775 if (Status == STATUS_PENDING)
776 {
777 Status = NtWaitForSingleObject(hNamedPipe,
778 FALSE,
779 NULL);
780 if (!NT_SUCCESS(Status))
781 {
782 SetLastErrorByStatus(Status);
783 return(FALSE);
784 }
785 }
786
787 if (!NT_SUCCESS(Status))
788 {
789 SetLastErrorByStatus(Status);
790 return(FALSE);
791 }
792 return(TRUE);
793 }
794
795
796 /*
797 * @unimplemented
798 */
799 BOOL STDCALL
800 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
801 LPDWORD lpState,
802 LPDWORD lpCurInstances,
803 LPDWORD lpMaxCollectionCount,
804 LPDWORD lpCollectDataTimeout,
805 LPWSTR lpUserName,
806 DWORD nMaxUserNameSize)
807 {
808 IO_STATUS_BLOCK StatusBlock;
809 NTSTATUS Status;
810
811 if (lpState != NULL)
812 {
813 FILE_PIPE_INFORMATION PipeInfo;
814
815 Status = NtQueryInformationFile(hNamedPipe,
816 &StatusBlock,
817 &PipeInfo,
818 sizeof(FILE_PIPE_INFORMATION),
819 FilePipeInformation);
820 if (!NT_SUCCESS(Status))
821 {
822 SetLastErrorByStatus(Status);
823 return FALSE;
824 }
825
826 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
827 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
828 }
829
830 if(lpCurInstances != NULL)
831 {
832 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
833
834 Status = NtQueryInformationFile(hNamedPipe,
835 &StatusBlock,
836 &LocalInfo,
837 sizeof(FILE_PIPE_LOCAL_INFORMATION),
838 FilePipeLocalInformation);
839 if(!NT_SUCCESS(Status))
840 {
841 SetLastErrorByStatus(Status);
842 return FALSE;
843 }
844
845 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
846 }
847
848 if(lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
849 {
850 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
851
852 Status = NtQueryInformationFile(hNamedPipe,
853 &StatusBlock,
854 &RemoteInfo,
855 sizeof(FILE_PIPE_REMOTE_INFORMATION),
856 FilePipeRemoteInformation);
857 if(!NT_SUCCESS(Status))
858 {
859 SetLastErrorByStatus(Status);
860 return FALSE;
861 }
862
863 if(lpMaxCollectionCount != NULL)
864 {
865 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
866 }
867
868 if(lpCollectDataTimeout != NULL)
869 {
870 /* FIXME */
871 *lpCollectDataTimeout = 0;
872 }
873 }
874
875 if(lpUserName != NULL)
876 {
877 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
878 retreive the user name with GetUserName(), revert the impersonation
879 and finally restore the thread token */
880 }
881
882 return TRUE;
883 }
884
885
886 /*
887 * @implemented
888 */
889 BOOL STDCALL
890 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
891 LPDWORD lpState,
892 LPDWORD lpCurInstances,
893 LPDWORD lpMaxCollectionCount,
894 LPDWORD lpCollectDataTimeout,
895 LPSTR lpUserName,
896 DWORD nMaxUserNameSize)
897 {
898 UNICODE_STRING UserNameW;
899 ANSI_STRING UserNameA;
900 BOOL Ret;
901
902 if(lpUserName != NULL)
903 {
904 UserNameW.Length = 0;
905 UserNameW.MaximumLength = nMaxUserNameSize * sizeof(WCHAR);
906 UserNameW.Buffer = HeapAlloc(GetCurrentProcess(), 0, UserNameW.MaximumLength);
907
908 UserNameA.Buffer = lpUserName;
909 UserNameA.Length = 0;
910 UserNameA.MaximumLength = nMaxUserNameSize;
911 }
912
913 Ret = GetNamedPipeHandleStateW(hNamedPipe,
914 lpState,
915 lpCurInstances,
916 lpMaxCollectionCount,
917 lpCollectDataTimeout,
918 UserNameW.Buffer,
919 nMaxUserNameSize);
920
921 if(Ret && lpUserName != NULL)
922 {
923 NTSTATUS Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
924 if(!NT_SUCCESS(Status))
925 {
926 SetLastErrorByStatus(Status);
927 Ret = FALSE;
928 }
929 }
930
931 if(UserNameW.Buffer != NULL)
932 {
933 HeapFree(GetCurrentProcess(), 0, UserNameW.Buffer);
934 }
935
936 return Ret;
937 }
938
939
940 /*
941 * @implemented
942 */
943 BOOL STDCALL
944 GetNamedPipeInfo(HANDLE hNamedPipe,
945 LPDWORD lpFlags,
946 LPDWORD lpOutBufferSize,
947 LPDWORD lpInBufferSize,
948 LPDWORD lpMaxInstances)
949 {
950 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
951 IO_STATUS_BLOCK StatusBlock;
952 NTSTATUS Status;
953
954 Status = NtQueryInformationFile(hNamedPipe,
955 &StatusBlock,
956 &PipeLocalInformation,
957 sizeof(FILE_PIPE_LOCAL_INFORMATION),
958 FilePipeLocalInformation);
959 if (!NT_SUCCESS(Status))
960 {
961 SetLastErrorByStatus(Status);
962 return(FALSE);
963 }
964
965 if (lpFlags != NULL)
966 {
967 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
968 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
969 }
970
971 if (lpOutBufferSize != NULL)
972 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
973
974 if (lpInBufferSize != NULL)
975 *lpInBufferSize = PipeLocalInformation.InboundQuota;
976
977 if (lpMaxInstances != NULL)
978 {
979 if (PipeLocalInformation.MaximumInstances >= 255)
980 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
981 else
982 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
983 }
984
985 return(TRUE);
986 }
987
988
989 /*
990 * @implemented
991 */
992 BOOL STDCALL
993 PeekNamedPipe(HANDLE hNamedPipe,
994 LPVOID lpBuffer,
995 DWORD nBufferSize,
996 LPDWORD lpBytesRead,
997 LPDWORD lpTotalBytesAvail,
998 LPDWORD lpBytesLeftThisMessage)
999 {
1000 PFILE_PIPE_PEEK_BUFFER Buffer;
1001 IO_STATUS_BLOCK Iosb;
1002 ULONG BufferSize;
1003 NTSTATUS Status;
1004
1005 BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
1006 Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1007 0,
1008 BufferSize);
1009
1010 Status = NtFsControlFile(hNamedPipe,
1011 NULL,
1012 NULL,
1013 NULL,
1014 &Iosb,
1015 FSCTL_PIPE_PEEK,
1016 NULL,
1017 0,
1018 Buffer,
1019 BufferSize);
1020 if (Status == STATUS_PENDING)
1021 {
1022 Status = NtWaitForSingleObject(hNamedPipe,
1023 FALSE,
1024 NULL);
1025 if (NT_SUCCESS(Status))
1026 Status = Iosb.Status;
1027 }
1028
1029 if (Status == STATUS_BUFFER_OVERFLOW)
1030 {
1031 Status = STATUS_SUCCESS;
1032 }
1033
1034 if (!NT_SUCCESS(Status))
1035 {
1036 RtlFreeHeap(RtlGetProcessHeap(),
1037 0,
1038 Buffer);
1039 SetLastErrorByStatus(Status);
1040 return(FALSE);
1041 }
1042
1043 if (lpTotalBytesAvail != NULL)
1044 {
1045 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1046 }
1047
1048 if (lpBytesRead != NULL)
1049 {
1050 *lpBytesRead = Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER);
1051 }
1052
1053 if (lpBytesLeftThisMessage != NULL)
1054 {
1055 *lpBytesLeftThisMessage = Buffer->MessageLength -
1056 (Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER));
1057 }
1058
1059 if (lpBuffer != NULL)
1060 {
1061 memcpy(lpBuffer, Buffer->Data,
1062 min(nBufferSize, Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER)));
1063 }
1064
1065 RtlFreeHeap(RtlGetProcessHeap(),
1066 0,
1067 Buffer);
1068
1069 return(TRUE);
1070 }
1071
1072
1073 /*
1074 * @implemented
1075 */
1076 BOOL STDCALL
1077 TransactNamedPipe(IN HANDLE hNamedPipe,
1078 IN LPVOID lpInBuffer,
1079 IN DWORD nInBufferSize,
1080 OUT LPVOID lpOutBuffer,
1081 IN DWORD nOutBufferSize,
1082 OUT LPDWORD lpBytesRead OPTIONAL,
1083 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1084 {
1085 NTSTATUS Status;
1086
1087 if (lpBytesRead != NULL)
1088 {
1089 *lpBytesRead = 0;
1090 }
1091
1092 if (lpOverlapped != NULL)
1093 {
1094 PVOID ApcContext;
1095
1096 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1097 lpOverlapped->Internal = STATUS_PENDING;
1098
1099 Status = NtFsControlFile(hNamedPipe,
1100 lpOverlapped->hEvent,
1101 NULL,
1102 ApcContext,
1103 (PIO_STATUS_BLOCK)lpOverlapped,
1104 FSCTL_PIPE_TRANSCEIVE,
1105 lpInBuffer,
1106 nInBufferSize,
1107 lpOutBuffer,
1108 nOutBufferSize);
1109
1110 /* return FALSE in case of failure and pending operations! */
1111 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1112 {
1113 SetLastErrorByStatus(Status);
1114 return FALSE;
1115 }
1116
1117 if (lpBytesRead != NULL)
1118 {
1119 *lpBytesRead = lpOverlapped->InternalHigh;
1120 }
1121 }
1122 else
1123 {
1124 IO_STATUS_BLOCK Iosb;
1125
1126 Status = NtFsControlFile(hNamedPipe,
1127 NULL,
1128 NULL,
1129 NULL,
1130 &Iosb,
1131 FSCTL_PIPE_TRANSCEIVE,
1132 lpInBuffer,
1133 nInBufferSize,
1134 lpOutBuffer,
1135 nOutBufferSize);
1136
1137 /* wait in case operation is pending */
1138 if (Status == STATUS_PENDING)
1139 {
1140 Status = NtWaitForSingleObject(hNamedPipe,
1141 FALSE,
1142 NULL);
1143 if (NT_SUCCESS(Status))
1144 {
1145 Status = Iosb.Status;
1146 }
1147 }
1148
1149 if (NT_SUCCESS(Status))
1150 {
1151 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1152 check that case either and crashes (only after the operation
1153 completed) */
1154 *lpBytesRead = Iosb.Information;
1155 }
1156 else
1157 {
1158 SetLastErrorByStatus(Status);
1159 return FALSE;
1160 }
1161 }
1162
1163 return TRUE;
1164 }
1165
1166 /* EOF */