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