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