d62527e12a50f0c6b36f0ad5b3d981b49473ad6a
[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 #include <wine/debug.h>
14
15 WINE_DEFAULT_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 Basep8BitStringToHeapUnicodeString(&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 return FALSE;
500 }
501
502 /* Check what timeout we got */
503 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
504 {
505 /* Don't use a timeout */
506 WaitPipe.TimeoutSpecified = FALSE;
507 }
508 else
509 {
510 /* Check if we should wait forever */
511 if (nTimeOut == NMPWAIT_WAIT_FOREVER)
512 {
513 /* Set the max */
514 WaitPipe.Timeout.LowPart = 0;
515 WaitPipe.Timeout.HighPart = 0x80000000;
516 }
517 else
518 {
519 /* Convert to NT format */
520 WaitPipe.Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut);
521 }
522
523 /* In both cases, we do have a timeout */
524 WaitPipe.TimeoutSpecified = TRUE;
525 }
526
527 Status = NtFsControlFile(FileHandle,
528 NULL,
529 NULL,
530 NULL,
531 &Iosb,
532 FSCTL_PIPE_WAIT,
533 &WaitPipe,
534 sizeof(WaitPipe),
535 NULL,
536 0);
537 NtClose(FileHandle);
538 if (!NT_SUCCESS(Status))
539 {
540 SetLastErrorByStatus(Status);
541 return FALSE;
542 }
543
544 return TRUE;
545 }
546 #endif
547
548
549 /*
550 * @implemented
551 */
552 BOOL
553 WINAPI
554 ConnectNamedPipe(IN HANDLE hNamedPipe,
555 IN LPOVERLAPPED lpOverlapped)
556 {
557 NTSTATUS Status;
558
559 if (lpOverlapped != NULL)
560 {
561 PVOID ApcContext;
562
563 lpOverlapped->Internal = STATUS_PENDING;
564 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
565
566 Status = NtFsControlFile(hNamedPipe,
567 lpOverlapped->hEvent,
568 NULL,
569 ApcContext,
570 (PIO_STATUS_BLOCK)lpOverlapped,
571 FSCTL_PIPE_LISTEN,
572 NULL,
573 0,
574 NULL,
575 0);
576
577 /* return FALSE in case of failure and pending operations! */
578 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
579 {
580 SetLastErrorByStatus(Status);
581 return FALSE;
582 }
583 }
584 else
585 {
586 IO_STATUS_BLOCK Iosb;
587
588 Status = NtFsControlFile(hNamedPipe,
589 NULL,
590 NULL,
591 NULL,
592 &Iosb,
593 FSCTL_PIPE_LISTEN,
594 NULL,
595 0,
596 NULL,
597 0);
598
599 /* wait in case operation is pending */
600 if (Status == STATUS_PENDING)
601 {
602 Status = NtWaitForSingleObject(hNamedPipe,
603 FALSE,
604 NULL);
605 if (NT_SUCCESS(Status))
606 {
607 Status = Iosb.Status;
608 }
609 }
610
611 if (!NT_SUCCESS(Status))
612 {
613 SetLastErrorByStatus(Status);
614 return FALSE;
615 }
616 }
617
618 return TRUE;
619 }
620
621
622 /*
623 * @implemented
624 */
625 BOOL
626 WINAPI
627 SetNamedPipeHandleState(HANDLE hNamedPipe,
628 LPDWORD lpMode,
629 LPDWORD lpMaxCollectionCount,
630 LPDWORD lpCollectDataTimeout)
631 {
632 IO_STATUS_BLOCK Iosb;
633 NTSTATUS Status;
634
635 /* Check if the Mode is being changed */
636 if (lpMode)
637 {
638 FILE_PIPE_INFORMATION Settings;
639
640 /* Set the Completion Mode */
641 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
642 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
643
644 /* Set the Read Mode */
645 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
646 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
647
648 /* Send the changes to the Driver */
649 Status = NtSetInformationFile(hNamedPipe,
650 &Iosb,
651 &Settings,
652 sizeof(FILE_PIPE_INFORMATION),
653 FilePipeInformation);
654 if (!NT_SUCCESS(Status))
655 {
656 SetLastErrorByStatus(Status);
657 return FALSE;
658 }
659 }
660
661 /* Check if the Collection count or Timeout are being changed */
662 if (lpMaxCollectionCount || lpCollectDataTimeout)
663 {
664 FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
665
666 /* Setting one without the other would delete it, so we read old one */
667 if (!lpMaxCollectionCount || !lpCollectDataTimeout)
668 {
669 Status = NtQueryInformationFile(hNamedPipe,
670 &Iosb,
671 &RemoteSettings,
672 sizeof(FILE_PIPE_REMOTE_INFORMATION),
673 FilePipeRemoteInformation);
674 if (!NT_SUCCESS(Status))
675 {
676 SetLastErrorByStatus(Status);
677 return FALSE;
678 }
679 }
680
681 /* Now set the new settings */
682 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
683 *lpMaxCollectionCount :
684 RemoteSettings.MaximumCollectionCount;
685 if (lpCollectDataTimeout)
686 {
687 /* Convert it to Quad */
688 RemoteSettings.CollectDataTime.QuadPart =
689 -(LONGLONG)UInt32x32To64(10000, *lpCollectDataTimeout);
690 }
691
692 /* Tell the driver to change them */
693 Status = NtSetInformationFile(hNamedPipe,
694 &Iosb,
695 &RemoteSettings,
696 sizeof(FILE_PIPE_REMOTE_INFORMATION),
697 FilePipeRemoteInformation);
698 if (!NT_SUCCESS(Status))
699 {
700 SetLastErrorByStatus(Status);
701 return FALSE;
702 }
703 }
704
705 return TRUE;
706 }
707
708
709 /*
710 * @implemented
711 */
712 BOOL
713 WINAPI
714 CallNamedPipeA(LPCSTR lpNamedPipeName,
715 LPVOID lpInBuffer,
716 DWORD nInBufferSize,
717 LPVOID lpOutBuffer,
718 DWORD nOutBufferSize,
719 LPDWORD lpBytesRead,
720 DWORD nTimeOut)
721 {
722 PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
723 ANSI_STRING AnsiPipe;
724
725 /* Initialize the string as ANSI_STRING and convert to Unicode */
726 RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName);
727 RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE);
728
729 /* Call the Unicode function */
730 return CallNamedPipeW(PipeName->Buffer,
731 lpInBuffer,
732 nInBufferSize,
733 lpOutBuffer,
734 nOutBufferSize,
735 lpBytesRead,
736 nTimeOut);
737 }
738
739
740 /*
741 * @implemented
742 */
743 BOOL
744 WINAPI
745 CallNamedPipeW(LPCWSTR lpNamedPipeName,
746 LPVOID lpInBuffer,
747 DWORD nInBufferSize,
748 LPVOID lpOutBuffer,
749 DWORD nOutBufferSize,
750 LPDWORD lpBytesRead,
751 DWORD nTimeOut)
752 {
753 HANDLE hPipe;
754 BOOL bRetry = TRUE;
755 BOOL bError;
756 DWORD dwPipeMode;
757
758 while (TRUE)
759 {
760 /* Try creating it */
761 hPipe = CreateFileW(lpNamedPipeName,
762 GENERIC_READ | GENERIC_WRITE,
763 FILE_SHARE_READ | FILE_SHARE_WRITE,
764 NULL,
765 OPEN_EXISTING,
766 FILE_ATTRIBUTE_NORMAL,
767 NULL);
768
769 /* Success, break out */
770 if (hPipe != INVALID_HANDLE_VALUE)
771 break;
772
773 /* Already tried twice, give up */
774 if (bRetry == FALSE)
775 return FALSE;
776
777 /* Wait on it */
778 WaitNamedPipeW(lpNamedPipeName, nTimeOut);
779
780 /* Get ready to try again */
781 bRetry = FALSE;
782 }
783
784 /* Set the pipe mode */
785 dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
786 bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL);
787 if (!bError)
788 {
789 /* Couldn't change state, fail */
790 CloseHandle(hPipe);
791 return FALSE;
792 }
793
794 /* Do the transact */
795 bError = TransactNamedPipe(hPipe,
796 lpInBuffer,
797 nInBufferSize,
798 lpOutBuffer,
799 nOutBufferSize,
800 lpBytesRead,
801 NULL);
802
803 /* Close the handle */
804 CloseHandle(hPipe);
805
806 return bError;
807 }
808
809
810 /*
811 * @implemented
812 */
813 BOOL
814 WINAPI
815 DisconnectNamedPipe(HANDLE hNamedPipe)
816 {
817 IO_STATUS_BLOCK Iosb;
818 NTSTATUS Status;
819
820 /* Send the FSCTL to the driver */
821 Status = NtFsControlFile(hNamedPipe,
822 NULL,
823 NULL,
824 NULL,
825 &Iosb,
826 FSCTL_PIPE_DISCONNECT,
827 NULL,
828 0,
829 NULL,
830 0);
831 if (Status == STATUS_PENDING)
832 {
833 /* Wait on NPFS to finish and get updated status */
834 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
835 if (NT_SUCCESS(Status))
836 Status = Iosb.Status;
837 }
838
839 /* Check for error */
840 if (!NT_SUCCESS(Status))
841 {
842 /* Fail */
843 SetLastErrorByStatus(Status);
844 return FALSE;
845 }
846
847 return TRUE;
848 }
849
850
851 /*
852 * @unimplemented
853 */
854 BOOL
855 WINAPI
856 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
857 LPDWORD lpState,
858 LPDWORD lpCurInstances,
859 LPDWORD lpMaxCollectionCount,
860 LPDWORD lpCollectDataTimeout,
861 LPWSTR lpUserName,
862 DWORD nMaxUserNameSize)
863 {
864 IO_STATUS_BLOCK StatusBlock;
865 NTSTATUS Status;
866
867 if (lpState != NULL)
868 {
869 FILE_PIPE_INFORMATION PipeInfo;
870
871 Status = NtQueryInformationFile(hNamedPipe,
872 &StatusBlock,
873 &PipeInfo,
874 sizeof(FILE_PIPE_INFORMATION),
875 FilePipeInformation);
876 if (!NT_SUCCESS(Status))
877 {
878 SetLastErrorByStatus(Status);
879 return FALSE;
880 }
881
882 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
883 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
884 }
885
886 if(lpCurInstances != NULL)
887 {
888 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
889
890 Status = NtQueryInformationFile(hNamedPipe,
891 &StatusBlock,
892 &LocalInfo,
893 sizeof(FILE_PIPE_LOCAL_INFORMATION),
894 FilePipeLocalInformation);
895 if (!NT_SUCCESS(Status))
896 {
897 SetLastErrorByStatus(Status);
898 return FALSE;
899 }
900
901 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
902 }
903
904 if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
905 {
906 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
907
908 Status = NtQueryInformationFile(hNamedPipe,
909 &StatusBlock,
910 &RemoteInfo,
911 sizeof(FILE_PIPE_REMOTE_INFORMATION),
912 FilePipeRemoteInformation);
913 if (!NT_SUCCESS(Status))
914 {
915 SetLastErrorByStatus(Status);
916 return FALSE;
917 }
918
919 if (lpMaxCollectionCount != NULL)
920 {
921 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
922 }
923
924 if(lpCollectDataTimeout != NULL)
925 {
926 /* FIXME */
927 *lpCollectDataTimeout = 0;
928 }
929 }
930
931 if (lpUserName != NULL)
932 {
933 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
934 retreive the user name with GetUserName(), revert the impersonation
935 and finally restore the thread token */
936 }
937
938 return TRUE;
939 }
940
941
942 /*
943 * @implemented
944 */
945 BOOL
946 WINAPI
947 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
948 LPDWORD lpState,
949 LPDWORD lpCurInstances,
950 LPDWORD lpMaxCollectionCount,
951 LPDWORD lpCollectDataTimeout,
952 LPSTR lpUserName,
953 DWORD nMaxUserNameSize)
954 {
955 UNICODE_STRING UserNameW = { 0, 0, NULL };
956 ANSI_STRING UserNameA;
957 BOOL Ret;
958
959 if(lpUserName != NULL)
960 {
961 UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR);
962 UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength);
963 if (UserNameW.Buffer == NULL)
964 {
965 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
966 return FALSE;
967 }
968
969 UserNameA.Buffer = lpUserName;
970 UserNameA.Length = 0;
971 UserNameA.MaximumLength = (USHORT)nMaxUserNameSize;
972 }
973
974 Ret = GetNamedPipeHandleStateW(hNamedPipe,
975 lpState,
976 lpCurInstances,
977 lpMaxCollectionCount,
978 lpCollectDataTimeout,
979 UserNameW.Buffer,
980 nMaxUserNameSize);
981 if (Ret && lpUserName != NULL)
982 {
983 NTSTATUS Status;
984
985 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
986 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
987 if (!NT_SUCCESS(Status))
988 {
989 SetLastErrorByStatus(Status);
990 Ret = FALSE;
991 }
992 }
993
994 if (UserNameW.Buffer != NULL)
995 {
996 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
997 }
998
999 return Ret;
1000 }
1001
1002
1003 /*
1004 * @implemented
1005 */
1006 BOOL
1007 WINAPI
1008 GetNamedPipeInfo(HANDLE hNamedPipe,
1009 LPDWORD lpFlags,
1010 LPDWORD lpOutBufferSize,
1011 LPDWORD lpInBufferSize,
1012 LPDWORD lpMaxInstances)
1013 {
1014 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
1015 IO_STATUS_BLOCK StatusBlock;
1016 NTSTATUS Status;
1017
1018 Status = NtQueryInformationFile(hNamedPipe,
1019 &StatusBlock,
1020 &PipeLocalInformation,
1021 sizeof(FILE_PIPE_LOCAL_INFORMATION),
1022 FilePipeLocalInformation);
1023 if (!NT_SUCCESS(Status))
1024 {
1025 SetLastErrorByStatus(Status);
1026 return FALSE;
1027 }
1028
1029 if (lpFlags != NULL)
1030 {
1031 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
1032 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
1033 }
1034
1035 if (lpOutBufferSize != NULL)
1036 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
1037
1038 if (lpInBufferSize != NULL)
1039 *lpInBufferSize = PipeLocalInformation.InboundQuota;
1040
1041 if (lpMaxInstances != NULL)
1042 {
1043 if (PipeLocalInformation.MaximumInstances >= 255)
1044 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
1045 else
1046 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
1047 }
1048
1049 return TRUE;
1050 }
1051
1052
1053 /*
1054 * @implemented
1055 */
1056 BOOL
1057 WINAPI
1058 PeekNamedPipe(HANDLE hNamedPipe,
1059 LPVOID lpBuffer,
1060 DWORD nBufferSize,
1061 LPDWORD lpBytesRead,
1062 LPDWORD lpTotalBytesAvail,
1063 LPDWORD lpBytesLeftThisMessage)
1064 {
1065 PFILE_PIPE_PEEK_BUFFER Buffer;
1066 IO_STATUS_BLOCK Iosb;
1067 ULONG BufferSize;
1068 ULONG BytesRead;
1069 NTSTATUS Status;
1070
1071 /* Calculate the buffer space that we'll need and allocate it */
1072 BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
1073 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1074 if (Buffer == NULL)
1075 {
1076 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1077 return FALSE;
1078 }
1079
1080 /* Tell the driver to seek */
1081 Status = NtFsControlFile(hNamedPipe,
1082 NULL,
1083 NULL,
1084 NULL,
1085 &Iosb,
1086 FSCTL_PIPE_PEEK,
1087 NULL,
1088 0,
1089 Buffer,
1090 BufferSize);
1091 if (Status == STATUS_PENDING)
1092 {
1093 /* Wait for npfs to be done, and update the status */
1094 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
1095 if (NT_SUCCESS(Status))
1096 Status = Iosb.Status;
1097 }
1098
1099 /* Overflow is success for us */
1100 if (Status == STATUS_BUFFER_OVERFLOW)
1101 Status = STATUS_SUCCESS;
1102
1103 /* If we failed */
1104 if (!NT_SUCCESS(Status))
1105 {
1106 /* Free the buffer and return failure */
1107 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1108 SetLastErrorByStatus(Status);
1109 return FALSE;
1110 }
1111
1112 /* Check if caller requested bytes available */
1113 if (lpTotalBytesAvail)
1114 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1115
1116 /* Calculate the bytes returned, minus our structure overhead */
1117 BytesRead = (ULONG)(Iosb.Information -
1118 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1119
1120 /* Check if caller requested bytes read */
1121 if (lpBytesRead)
1122 {
1123 /* Return the bytes read */
1124 *lpBytesRead = BytesRead;
1125 }
1126
1127 /* Check if caller requested bytes left */
1128 if (lpBytesLeftThisMessage)
1129 {
1130 /* Calculate total minus what we returned and our structure overhead */
1131 *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead;
1132 }
1133
1134 /* Check if the caller wanted to see the actual data */
1135 if (lpBuffer)
1136 {
1137 /* Give him what he wants */
1138 RtlCopyMemory(lpBuffer,
1139 Buffer->Data,
1140 BytesRead);
1141 }
1142
1143 /* Free the buffer */
1144 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1145
1146 return TRUE;
1147 }
1148
1149
1150 /*
1151 * @implemented
1152 */
1153 BOOL
1154 WINAPI
1155 TransactNamedPipe(IN HANDLE hNamedPipe,
1156 IN LPVOID lpInBuffer,
1157 IN DWORD nInBufferSize,
1158 OUT LPVOID lpOutBuffer,
1159 IN DWORD nOutBufferSize,
1160 OUT LPDWORD lpBytesRead OPTIONAL,
1161 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1162 {
1163 NTSTATUS Status;
1164
1165 if (lpBytesRead != NULL)
1166 {
1167 *lpBytesRead = 0;
1168 }
1169
1170 if (lpOverlapped != NULL)
1171 {
1172 PVOID ApcContext;
1173
1174 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1175 lpOverlapped->Internal = STATUS_PENDING;
1176
1177 Status = NtFsControlFile(hNamedPipe,
1178 lpOverlapped->hEvent,
1179 NULL,
1180 ApcContext,
1181 (PIO_STATUS_BLOCK)lpOverlapped,
1182 FSCTL_PIPE_TRANSCEIVE,
1183 lpInBuffer,
1184 nInBufferSize,
1185 lpOutBuffer,
1186 nOutBufferSize);
1187 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1188 {
1189 SetLastErrorByStatus(Status);
1190 return FALSE;
1191 }
1192
1193 if (lpBytesRead != NULL)
1194 {
1195 *lpBytesRead = lpOverlapped->InternalHigh;
1196 }
1197 }
1198 else
1199 {
1200 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1201 IO_STATUS_BLOCK Iosb;
1202
1203 Status = NtFsControlFile(hNamedPipe,
1204 NULL,
1205 NULL,
1206 NULL,
1207 &Iosb,
1208 FSCTL_PIPE_TRANSCEIVE,
1209 lpInBuffer,
1210 nInBufferSize,
1211 lpOutBuffer,
1212 nOutBufferSize);
1213 if (Status == STATUS_PENDING)
1214 {
1215 Status = NtWaitForSingleObject(hNamedPipe,
1216 FALSE,
1217 NULL);
1218 if (NT_SUCCESS(Status))
1219 Status = Iosb.Status;
1220 }
1221
1222 if (NT_SUCCESS(Status))
1223 {
1224 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1225 check that case either and crashes (only after the operation
1226 completed) */
1227 *lpBytesRead = Iosb.Information;
1228 }
1229 else
1230 {
1231 SetLastErrorByStatus(Status);
1232 return FALSE;
1233 }
1234 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1235 DWORD nActualBytes;
1236
1237 while (0 != nInBufferSize &&
1238 WriteFile(hNamedPipe, lpInBuffer, nInBufferSize, &nActualBytes,
1239 NULL))
1240 {
1241 lpInBuffer = (LPVOID)((char *) lpInBuffer + nActualBytes);
1242 nInBufferSize -= nActualBytes;
1243 }
1244
1245 if (0 != nInBufferSize)
1246 {
1247 /* Must have dropped out of the while 'cause WriteFile failed */
1248 return FALSE;
1249 }
1250
1251 if (!ReadFile(hNamedPipe, lpOutBuffer, nOutBufferSize, &nActualBytes,
1252 NULL))
1253 {
1254 return FALSE;
1255 }
1256
1257 if (NULL != lpBytesRead)
1258 {
1259 *lpBytesRead = nActualBytes;
1260 }
1261 #endif
1262 }
1263
1264 return TRUE;
1265 }
1266
1267 /* EOF */