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