[SHELL/EXPERIMENTS]
[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 = UInt32x32To64(nDefaultTimeOut, -10000);
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 = UInt32x32To64(-10000, nTimeOut);
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 =
703 -(LONGLONG)UInt32x32To64(10000, *lpCollectDataTimeout);
704 }
705
706 /* Tell the driver to change them */
707 Status = NtSetInformationFile(hNamedPipe,
708 &Iosb,
709 &RemoteSettings,
710 sizeof(FILE_PIPE_REMOTE_INFORMATION),
711 FilePipeRemoteInformation);
712 if (!NT_SUCCESS(Status))
713 {
714 BaseSetLastNTError(Status);
715 return FALSE;
716 }
717 }
718
719 return TRUE;
720 }
721
722
723 /*
724 * @implemented
725 */
726 BOOL
727 WINAPI
728 CallNamedPipeA(LPCSTR lpNamedPipeName,
729 LPVOID lpInBuffer,
730 DWORD nInBufferSize,
731 LPVOID lpOutBuffer,
732 DWORD nOutBufferSize,
733 LPDWORD lpBytesRead,
734 DWORD nTimeOut)
735 {
736 PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
737 ANSI_STRING AnsiPipe;
738
739 /* Initialize the string as ANSI_STRING and convert to Unicode */
740 RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName);
741 RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE);
742
743 /* Call the Unicode function */
744 return CallNamedPipeW(PipeName->Buffer,
745 lpInBuffer,
746 nInBufferSize,
747 lpOutBuffer,
748 nOutBufferSize,
749 lpBytesRead,
750 nTimeOut);
751 }
752
753
754 /*
755 * @implemented
756 */
757 BOOL
758 WINAPI
759 CallNamedPipeW(LPCWSTR lpNamedPipeName,
760 LPVOID lpInBuffer,
761 DWORD nInBufferSize,
762 LPVOID lpOutBuffer,
763 DWORD nOutBufferSize,
764 LPDWORD lpBytesRead,
765 DWORD nTimeOut)
766 {
767 HANDLE hPipe;
768 BOOL bRetry = TRUE;
769 BOOL bError;
770 DWORD dwPipeMode;
771
772 while (TRUE)
773 {
774 /* Try creating it */
775 hPipe = CreateFileW(lpNamedPipeName,
776 GENERIC_READ | GENERIC_WRITE,
777 FILE_SHARE_READ | FILE_SHARE_WRITE,
778 NULL,
779 OPEN_EXISTING,
780 FILE_ATTRIBUTE_NORMAL,
781 NULL);
782
783 /* Success, break out */
784 if (hPipe != INVALID_HANDLE_VALUE)
785 break;
786
787 /* Already tried twice, give up */
788 if (bRetry == FALSE)
789 return FALSE;
790
791 /* Wait on it */
792 WaitNamedPipeW(lpNamedPipeName, nTimeOut);
793
794 /* Get ready to try again */
795 bRetry = FALSE;
796 }
797
798 /* Set the pipe mode */
799 dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
800 bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL);
801 if (!bError)
802 {
803 /* Couldn't change state, fail */
804 CloseHandle(hPipe);
805 return FALSE;
806 }
807
808 /* Do the transact */
809 bError = TransactNamedPipe(hPipe,
810 lpInBuffer,
811 nInBufferSize,
812 lpOutBuffer,
813 nOutBufferSize,
814 lpBytesRead,
815 NULL);
816
817 /* Close the handle */
818 CloseHandle(hPipe);
819
820 return bError;
821 }
822
823
824 /*
825 * @implemented
826 */
827 BOOL
828 WINAPI
829 DisconnectNamedPipe(HANDLE hNamedPipe)
830 {
831 IO_STATUS_BLOCK Iosb;
832 NTSTATUS Status;
833
834 /* Send the FSCTL to the driver */
835 Status = NtFsControlFile(hNamedPipe,
836 NULL,
837 NULL,
838 NULL,
839 &Iosb,
840 FSCTL_PIPE_DISCONNECT,
841 NULL,
842 0,
843 NULL,
844 0);
845 if (Status == STATUS_PENDING)
846 {
847 /* Wait on NPFS to finish and get updated status */
848 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
849 if (NT_SUCCESS(Status))
850 Status = Iosb.Status;
851 }
852
853 /* Check for error */
854 if (!NT_SUCCESS(Status))
855 {
856 /* Fail */
857 BaseSetLastNTError(Status);
858 return FALSE;
859 }
860
861 return TRUE;
862 }
863
864
865 /*
866 * @unimplemented
867 */
868 BOOL
869 WINAPI
870 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
871 LPDWORD lpState,
872 LPDWORD lpCurInstances,
873 LPDWORD lpMaxCollectionCount,
874 LPDWORD lpCollectDataTimeout,
875 LPWSTR lpUserName,
876 DWORD nMaxUserNameSize)
877 {
878 IO_STATUS_BLOCK StatusBlock;
879 NTSTATUS Status;
880
881 if (lpState != NULL)
882 {
883 FILE_PIPE_INFORMATION PipeInfo;
884
885 Status = NtQueryInformationFile(hNamedPipe,
886 &StatusBlock,
887 &PipeInfo,
888 sizeof(FILE_PIPE_INFORMATION),
889 FilePipeInformation);
890 if (!NT_SUCCESS(Status))
891 {
892 BaseSetLastNTError(Status);
893 return FALSE;
894 }
895
896 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
897 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
898 }
899
900 if(lpCurInstances != NULL)
901 {
902 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
903
904 Status = NtQueryInformationFile(hNamedPipe,
905 &StatusBlock,
906 &LocalInfo,
907 sizeof(FILE_PIPE_LOCAL_INFORMATION),
908 FilePipeLocalInformation);
909 if (!NT_SUCCESS(Status))
910 {
911 BaseSetLastNTError(Status);
912 return FALSE;
913 }
914
915 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
916 }
917
918 if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
919 {
920 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
921
922 Status = NtQueryInformationFile(hNamedPipe,
923 &StatusBlock,
924 &RemoteInfo,
925 sizeof(FILE_PIPE_REMOTE_INFORMATION),
926 FilePipeRemoteInformation);
927 if (!NT_SUCCESS(Status))
928 {
929 BaseSetLastNTError(Status);
930 return FALSE;
931 }
932
933 if (lpMaxCollectionCount != NULL)
934 {
935 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
936 }
937
938 if(lpCollectDataTimeout != NULL)
939 {
940 /* FIXME */
941 *lpCollectDataTimeout = 0;
942 }
943 }
944
945 if (lpUserName != NULL)
946 {
947 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
948 retreive the user name with GetUserName(), revert the impersonation
949 and finally restore the thread token */
950 }
951
952 return TRUE;
953 }
954
955
956 /*
957 * @implemented
958 */
959 BOOL
960 WINAPI
961 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
962 LPDWORD lpState,
963 LPDWORD lpCurInstances,
964 LPDWORD lpMaxCollectionCount,
965 LPDWORD lpCollectDataTimeout,
966 LPSTR lpUserName,
967 DWORD nMaxUserNameSize)
968 {
969 UNICODE_STRING UserNameW = { 0, 0, NULL };
970 ANSI_STRING UserNameA;
971 BOOL Ret;
972
973 if(lpUserName != NULL)
974 {
975 UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR);
976 UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength);
977 if (UserNameW.Buffer == NULL)
978 {
979 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
980 return FALSE;
981 }
982
983 UserNameA.Buffer = lpUserName;
984 UserNameA.Length = 0;
985 UserNameA.MaximumLength = (USHORT)nMaxUserNameSize;
986 }
987
988 Ret = GetNamedPipeHandleStateW(hNamedPipe,
989 lpState,
990 lpCurInstances,
991 lpMaxCollectionCount,
992 lpCollectDataTimeout,
993 UserNameW.Buffer,
994 nMaxUserNameSize);
995 if (Ret && lpUserName != NULL)
996 {
997 NTSTATUS Status;
998
999 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
1000 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
1001 if (!NT_SUCCESS(Status))
1002 {
1003 BaseSetLastNTError(Status);
1004 Ret = FALSE;
1005 }
1006 }
1007
1008 if (UserNameW.Buffer != NULL)
1009 {
1010 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
1011 }
1012
1013 return Ret;
1014 }
1015
1016
1017 /*
1018 * @implemented
1019 */
1020 BOOL
1021 WINAPI
1022 GetNamedPipeInfo(HANDLE hNamedPipe,
1023 LPDWORD lpFlags,
1024 LPDWORD lpOutBufferSize,
1025 LPDWORD lpInBufferSize,
1026 LPDWORD lpMaxInstances)
1027 {
1028 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
1029 IO_STATUS_BLOCK StatusBlock;
1030 NTSTATUS Status;
1031
1032 Status = NtQueryInformationFile(hNamedPipe,
1033 &StatusBlock,
1034 &PipeLocalInformation,
1035 sizeof(FILE_PIPE_LOCAL_INFORMATION),
1036 FilePipeLocalInformation);
1037 if (!NT_SUCCESS(Status))
1038 {
1039 BaseSetLastNTError(Status);
1040 return FALSE;
1041 }
1042
1043 if (lpFlags != NULL)
1044 {
1045 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
1046 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
1047 }
1048
1049 if (lpOutBufferSize != NULL)
1050 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
1051
1052 if (lpInBufferSize != NULL)
1053 *lpInBufferSize = PipeLocalInformation.InboundQuota;
1054
1055 if (lpMaxInstances != NULL)
1056 {
1057 if (PipeLocalInformation.MaximumInstances >= 255)
1058 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
1059 else
1060 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
1061 }
1062
1063 return TRUE;
1064 }
1065
1066
1067 /*
1068 * @implemented
1069 */
1070 BOOL
1071 WINAPI
1072 PeekNamedPipe(HANDLE hNamedPipe,
1073 LPVOID lpBuffer,
1074 DWORD nBufferSize,
1075 LPDWORD lpBytesRead,
1076 LPDWORD lpTotalBytesAvail,
1077 LPDWORD lpBytesLeftThisMessage)
1078 {
1079 PFILE_PIPE_PEEK_BUFFER Buffer;
1080 IO_STATUS_BLOCK Iosb;
1081 ULONG BufferSize;
1082 ULONG BytesRead;
1083 NTSTATUS Status;
1084
1085 /* Calculate the buffer space that we'll need and allocate it */
1086 BufferSize = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[nBufferSize]);
1087 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1088 if (Buffer == NULL)
1089 {
1090 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1091 return FALSE;
1092 }
1093
1094 /* Tell the driver to seek */
1095 Status = NtFsControlFile(hNamedPipe,
1096 NULL,
1097 NULL,
1098 NULL,
1099 &Iosb,
1100 FSCTL_PIPE_PEEK,
1101 NULL,
1102 0,
1103 Buffer,
1104 BufferSize);
1105 if (Status == STATUS_PENDING)
1106 {
1107 /* Wait for npfs to be done, and update the status */
1108 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
1109 if (NT_SUCCESS(Status))
1110 Status = Iosb.Status;
1111 }
1112
1113 /* Overflow is success for us */
1114 if (Status == STATUS_BUFFER_OVERFLOW)
1115 Status = STATUS_SUCCESS;
1116
1117 /* If we failed */
1118 if (!NT_SUCCESS(Status))
1119 {
1120 /* Free the buffer and return failure */
1121 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1122 BaseSetLastNTError(Status);
1123 return FALSE;
1124 }
1125
1126 /* Check if caller requested bytes available */
1127 if (lpTotalBytesAvail)
1128 {
1129 /* Return bytes available */
1130 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1131 }
1132
1133 /* Calculate the bytes returned, minus our structure overhead */
1134 BytesRead = (ULONG)(Iosb.Information -
1135 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1136 ASSERT(BytesRead <= nBufferSize);
1137
1138 /* Check if caller requested bytes read */
1139 if (lpBytesRead)
1140 {
1141 /* Return the bytes read */
1142 *lpBytesRead = BytesRead;
1143 }
1144
1145 /* Check if caller requested bytes left */
1146 if (lpBytesLeftThisMessage)
1147 {
1148 /* Calculate total minus what we returned and our structure overhead */
1149 *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead;
1150 }
1151
1152 /* Check if the caller wanted to see the actual data */
1153 if (lpBuffer)
1154 {
1155 /* Give him what he wants */
1156 RtlCopyMemory(lpBuffer,
1157 Buffer->Data,
1158 BytesRead);
1159 }
1160
1161 /* Free the buffer */
1162 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1163
1164 return TRUE;
1165 }
1166
1167
1168 /*
1169 * @implemented
1170 */
1171 BOOL
1172 WINAPI
1173 TransactNamedPipe(IN HANDLE hNamedPipe,
1174 IN LPVOID lpInBuffer,
1175 IN DWORD nInBufferSize,
1176 OUT LPVOID lpOutBuffer,
1177 IN DWORD nOutBufferSize,
1178 OUT LPDWORD lpBytesRead OPTIONAL,
1179 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1180 {
1181 NTSTATUS Status;
1182
1183 if (lpBytesRead != NULL)
1184 {
1185 *lpBytesRead = 0;
1186 }
1187
1188 if (lpOverlapped != NULL)
1189 {
1190 PVOID ApcContext;
1191
1192 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1193 lpOverlapped->Internal = STATUS_PENDING;
1194
1195 Status = NtFsControlFile(hNamedPipe,
1196 lpOverlapped->hEvent,
1197 NULL,
1198 ApcContext,
1199 (PIO_STATUS_BLOCK)lpOverlapped,
1200 FSCTL_PIPE_TRANSCEIVE,
1201 lpInBuffer,
1202 nInBufferSize,
1203 lpOutBuffer,
1204 nOutBufferSize);
1205 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1206 {
1207 BaseSetLastNTError(Status);
1208 return FALSE;
1209 }
1210
1211 if (lpBytesRead != NULL)
1212 {
1213 *lpBytesRead = lpOverlapped->InternalHigh;
1214 }
1215 }
1216 else
1217 {
1218 IO_STATUS_BLOCK Iosb;
1219
1220 Status = NtFsControlFile(hNamedPipe,
1221 NULL,
1222 NULL,
1223 NULL,
1224 &Iosb,
1225 FSCTL_PIPE_TRANSCEIVE,
1226 lpInBuffer,
1227 nInBufferSize,
1228 lpOutBuffer,
1229 nOutBufferSize);
1230 if (Status == STATUS_PENDING)
1231 {
1232 Status = NtWaitForSingleObject(hNamedPipe,
1233 FALSE,
1234 NULL);
1235 if (NT_SUCCESS(Status))
1236 Status = Iosb.Status;
1237 }
1238
1239 if (NT_SUCCESS(Status))
1240 {
1241 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1242 check that case either and crashes (only after the operation
1243 completed) */
1244 *lpBytesRead = Iosb.Information;
1245 }
1246 else
1247 {
1248 BaseSetLastNTError(Status);
1249 return FALSE;
1250 }
1251 }
1252
1253 return TRUE;
1254 }
1255
1256 /* EOF */