7695bbe53be8efe60b21fa541de7b560fbe1a6ba
[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 STDCALL
668 CallNamedPipeA(LPCSTR lpNamedPipeName,
669 LPVOID lpInBuffer,
670 DWORD nInBufferSize,
671 LPVOID lpOutBuffer,
672 DWORD nOutBufferSize,
673 LPDWORD lpBytesRead,
674 DWORD nTimeOut)
675 {
676 UNICODE_STRING PipeName;
677 BOOL Result;
678
679 RtlCreateUnicodeStringFromAsciiz(&PipeName,
680 (LPSTR)lpNamedPipeName);
681
682 Result = CallNamedPipeW(PipeName.Buffer,
683 lpInBuffer,
684 nInBufferSize,
685 lpOutBuffer,
686 nOutBufferSize,
687 lpBytesRead,
688 nTimeOut);
689
690 RtlFreeUnicodeString(&PipeName);
691
692 return(Result);
693 }
694
695
696 /*
697 * @implemented
698 */
699 BOOL STDCALL
700 CallNamedPipeW(LPCWSTR lpNamedPipeName,
701 LPVOID lpInBuffer,
702 DWORD nInBufferSize,
703 LPVOID lpOutBuffer,
704 DWORD nOutBufferSize,
705 LPDWORD lpBytesRead,
706 DWORD nTimeOut)
707 {
708 HANDLE hPipe = INVALID_HANDLE_VALUE;
709 BOOL bRetry = TRUE;
710 BOOL bError = FALSE;
711 DWORD dwPipeMode;
712
713 while (TRUE)
714 {
715 hPipe = CreateFileW(lpNamedPipeName,
716 GENERIC_READ | GENERIC_WRITE,
717 FILE_SHARE_READ | FILE_SHARE_WRITE,
718 NULL,
719 OPEN_EXISTING,
720 FILE_ATTRIBUTE_NORMAL,
721 NULL);
722 if (hPipe != INVALID_HANDLE_VALUE)
723 break;
724
725 if (bRetry == FALSE)
726 return(FALSE);
727
728 WaitNamedPipeW(lpNamedPipeName,
729 nTimeOut);
730
731 bRetry = FALSE;
732 }
733
734 dwPipeMode = PIPE_READMODE_MESSAGE;
735 bError = SetNamedPipeHandleState(hPipe,
736 &dwPipeMode,
737 NULL,
738 NULL);
739 if (!bError)
740 {
741 CloseHandle(hPipe);
742 return(FALSE);
743 }
744
745 bError = TransactNamedPipe(hPipe,
746 lpInBuffer,
747 nInBufferSize,
748 lpOutBuffer,
749 nOutBufferSize,
750 lpBytesRead,
751 NULL);
752 CloseHandle(hPipe);
753
754 return(bError);
755 }
756
757
758 /*
759 * @implemented
760 */
761 BOOL STDCALL
762 DisconnectNamedPipe(HANDLE hNamedPipe)
763 {
764 IO_STATUS_BLOCK Iosb;
765 NTSTATUS Status;
766
767 Status = NtFsControlFile(hNamedPipe,
768 NULL,
769 NULL,
770 NULL,
771 &Iosb,
772 FSCTL_PIPE_DISCONNECT,
773 NULL,
774 0,
775 NULL,
776 0);
777 if (Status == STATUS_PENDING)
778 {
779 Status = NtWaitForSingleObject(hNamedPipe,
780 FALSE,
781 NULL);
782 if (!NT_SUCCESS(Status))
783 {
784 SetLastErrorByStatus(Status);
785 return(FALSE);
786 }
787 }
788
789 if (!NT_SUCCESS(Status))
790 {
791 SetLastErrorByStatus(Status);
792 return(FALSE);
793 }
794 return(TRUE);
795 }
796
797
798 /*
799 * @unimplemented
800 */
801 BOOL STDCALL
802 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
803 LPDWORD lpState,
804 LPDWORD lpCurInstances,
805 LPDWORD lpMaxCollectionCount,
806 LPDWORD lpCollectDataTimeout,
807 LPWSTR lpUserName,
808 DWORD nMaxUserNameSize)
809 {
810 IO_STATUS_BLOCK StatusBlock;
811 NTSTATUS Status;
812
813 if (lpState != NULL)
814 {
815 FILE_PIPE_INFORMATION PipeInfo;
816
817 Status = NtQueryInformationFile(hNamedPipe,
818 &StatusBlock,
819 &PipeInfo,
820 sizeof(FILE_PIPE_INFORMATION),
821 FilePipeInformation);
822 if (!NT_SUCCESS(Status))
823 {
824 SetLastErrorByStatus(Status);
825 return FALSE;
826 }
827
828 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
829 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
830 }
831
832 if(lpCurInstances != NULL)
833 {
834 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
835
836 Status = NtQueryInformationFile(hNamedPipe,
837 &StatusBlock,
838 &LocalInfo,
839 sizeof(FILE_PIPE_LOCAL_INFORMATION),
840 FilePipeLocalInformation);
841 if(!NT_SUCCESS(Status))
842 {
843 SetLastErrorByStatus(Status);
844 return FALSE;
845 }
846
847 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
848 }
849
850 if(lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
851 {
852 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
853
854 Status = NtQueryInformationFile(hNamedPipe,
855 &StatusBlock,
856 &RemoteInfo,
857 sizeof(FILE_PIPE_REMOTE_INFORMATION),
858 FilePipeRemoteInformation);
859 if(!NT_SUCCESS(Status))
860 {
861 SetLastErrorByStatus(Status);
862 return FALSE;
863 }
864
865 if(lpMaxCollectionCount != NULL)
866 {
867 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
868 }
869
870 if(lpCollectDataTimeout != NULL)
871 {
872 /* FIXME */
873 *lpCollectDataTimeout = 0;
874 }
875 }
876
877 if(lpUserName != NULL)
878 {
879 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
880 retreive the user name with GetUserName(), revert the impersonation
881 and finally restore the thread token */
882 }
883
884 return TRUE;
885 }
886
887
888 /*
889 * @implemented
890 */
891 BOOL STDCALL
892 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
893 LPDWORD lpState,
894 LPDWORD lpCurInstances,
895 LPDWORD lpMaxCollectionCount,
896 LPDWORD lpCollectDataTimeout,
897 LPSTR lpUserName,
898 DWORD nMaxUserNameSize)
899 {
900 UNICODE_STRING UserNameW;
901 ANSI_STRING UserNameA;
902 BOOL Ret;
903
904 if(lpUserName != NULL)
905 {
906 UserNameW.Length = 0;
907 UserNameW.MaximumLength = nMaxUserNameSize * sizeof(WCHAR);
908 UserNameW.Buffer = HeapAlloc(GetCurrentProcess(), 0, UserNameW.MaximumLength);
909
910 UserNameA.Buffer = lpUserName;
911 UserNameA.Length = 0;
912 UserNameA.MaximumLength = nMaxUserNameSize;
913 }
914
915 Ret = GetNamedPipeHandleStateW(hNamedPipe,
916 lpState,
917 lpCurInstances,
918 lpMaxCollectionCount,
919 lpCollectDataTimeout,
920 UserNameW.Buffer,
921 nMaxUserNameSize);
922
923 if(Ret && lpUserName != NULL)
924 {
925 NTSTATUS Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
926 if(!NT_SUCCESS(Status))
927 {
928 SetLastErrorByStatus(Status);
929 Ret = FALSE;
930 }
931 }
932
933 if(UserNameW.Buffer != NULL)
934 {
935 HeapFree(GetCurrentProcess(), 0, UserNameW.Buffer);
936 }
937
938 return Ret;
939 }
940
941
942 /*
943 * @implemented
944 */
945 BOOL STDCALL
946 GetNamedPipeInfo(HANDLE hNamedPipe,
947 LPDWORD lpFlags,
948 LPDWORD lpOutBufferSize,
949 LPDWORD lpInBufferSize,
950 LPDWORD lpMaxInstances)
951 {
952 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
953 IO_STATUS_BLOCK StatusBlock;
954 NTSTATUS Status;
955
956 Status = NtQueryInformationFile(hNamedPipe,
957 &StatusBlock,
958 &PipeLocalInformation,
959 sizeof(FILE_PIPE_LOCAL_INFORMATION),
960 FilePipeLocalInformation);
961 if (!NT_SUCCESS(Status))
962 {
963 SetLastErrorByStatus(Status);
964 return(FALSE);
965 }
966
967 if (lpFlags != NULL)
968 {
969 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
970 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
971 }
972
973 if (lpOutBufferSize != NULL)
974 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
975
976 if (lpInBufferSize != NULL)
977 *lpInBufferSize = PipeLocalInformation.InboundQuota;
978
979 if (lpMaxInstances != NULL)
980 {
981 if (PipeLocalInformation.MaximumInstances >= 255)
982 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
983 else
984 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
985 }
986
987 return(TRUE);
988 }
989
990
991 /*
992 * @implemented
993 */
994 BOOL STDCALL
995 PeekNamedPipe(HANDLE hNamedPipe,
996 LPVOID lpBuffer,
997 DWORD nBufferSize,
998 LPDWORD lpBytesRead,
999 LPDWORD lpTotalBytesAvail,
1000 LPDWORD lpBytesLeftThisMessage)
1001 {
1002 PFILE_PIPE_PEEK_BUFFER Buffer;
1003 IO_STATUS_BLOCK Iosb;
1004 ULONG BufferSize;
1005 NTSTATUS Status;
1006
1007 BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
1008 Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1009 0,
1010 BufferSize);
1011
1012 Status = NtFsControlFile(hNamedPipe,
1013 NULL,
1014 NULL,
1015 NULL,
1016 &Iosb,
1017 FSCTL_PIPE_PEEK,
1018 NULL,
1019 0,
1020 Buffer,
1021 BufferSize);
1022 if (Status == STATUS_PENDING)
1023 {
1024 Status = NtWaitForSingleObject(hNamedPipe,
1025 FALSE,
1026 NULL);
1027 if (NT_SUCCESS(Status))
1028 Status = Iosb.Status;
1029 }
1030
1031 if (Status == STATUS_BUFFER_OVERFLOW)
1032 {
1033 Status = STATUS_SUCCESS;
1034 }
1035
1036 if (!NT_SUCCESS(Status))
1037 {
1038 RtlFreeHeap(RtlGetProcessHeap(),
1039 0,
1040 Buffer);
1041 SetLastErrorByStatus(Status);
1042 return(FALSE);
1043 }
1044
1045 if (lpTotalBytesAvail != NULL)
1046 {
1047 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1048 }
1049
1050 if (lpBytesRead != NULL)
1051 {
1052 *lpBytesRead = Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER);
1053 }
1054
1055 if (lpBytesLeftThisMessage != NULL)
1056 {
1057 *lpBytesLeftThisMessage = Buffer->MessageLength -
1058 (Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER));
1059 }
1060
1061 if (lpBuffer != NULL)
1062 {
1063 memcpy(lpBuffer, Buffer->Data,
1064 min(nBufferSize, Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER)));
1065 }
1066
1067 RtlFreeHeap(RtlGetProcessHeap(),
1068 0,
1069 Buffer);
1070
1071 return(TRUE);
1072 }
1073
1074
1075 /*
1076 * @implemented
1077 */
1078 BOOL STDCALL
1079 TransactNamedPipe(IN HANDLE hNamedPipe,
1080 IN LPVOID lpInBuffer,
1081 IN DWORD nInBufferSize,
1082 OUT LPVOID lpOutBuffer,
1083 IN DWORD nOutBufferSize,
1084 OUT LPDWORD lpBytesRead OPTIONAL,
1085 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1086 {
1087 NTSTATUS Status;
1088
1089 if (lpBytesRead != NULL)
1090 {
1091 *lpBytesRead = 0;
1092 }
1093
1094 if (lpOverlapped != NULL)
1095 {
1096 PVOID ApcContext;
1097
1098 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1099 lpOverlapped->Internal = STATUS_PENDING;
1100
1101 Status = NtFsControlFile(hNamedPipe,
1102 lpOverlapped->hEvent,
1103 NULL,
1104 ApcContext,
1105 (PIO_STATUS_BLOCK)lpOverlapped,
1106 FSCTL_PIPE_TRANSCEIVE,
1107 lpInBuffer,
1108 nInBufferSize,
1109 lpOutBuffer,
1110 nOutBufferSize);
1111
1112 /* return FALSE in case of failure and pending operations! */
1113 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1114 {
1115 SetLastErrorByStatus(Status);
1116 return FALSE;
1117 }
1118
1119 if (lpBytesRead != NULL)
1120 {
1121 *lpBytesRead = lpOverlapped->InternalHigh;
1122 }
1123 }
1124 else
1125 {
1126 IO_STATUS_BLOCK Iosb;
1127
1128 Status = NtFsControlFile(hNamedPipe,
1129 NULL,
1130 NULL,
1131 NULL,
1132 &Iosb,
1133 FSCTL_PIPE_TRANSCEIVE,
1134 lpInBuffer,
1135 nInBufferSize,
1136 lpOutBuffer,
1137 nOutBufferSize);
1138
1139 /* wait in case operation is pending */
1140 if (Status == STATUS_PENDING)
1141 {
1142 Status = NtWaitForSingleObject(hNamedPipe,
1143 FALSE,
1144 NULL);
1145 if (NT_SUCCESS(Status))
1146 {
1147 Status = Iosb.Status;
1148 }
1149 }
1150
1151 if (NT_SUCCESS(Status))
1152 {
1153 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1154 check that case either and crashes (only after the operation
1155 completed) */
1156 *lpBytesRead = Iosb.Information;
1157 }
1158 else
1159 {
1160 SetLastErrorByStatus(Status);
1161 return FALSE;
1162 }
1163 }
1164
1165 return TRUE;
1166 }
1167
1168 /* EOF */