ee341580c258ca43020601bbf8fc561a491911f5
[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: dll/win32/kernel32/client/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 = FALSE;
348 UNICODE_STRING NameU;
349
350 /* Convert the name to Unicode */
351 if (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
360 /* Return result */
361 return r;
362 }
363
364 /*
365 * @implemented
366 */
367 BOOL
368 WINAPI
369 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
370 DWORD nTimeOut)
371 {
372 UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix;
373 ULONG NameLength;
374 ULONG i;
375 PWCHAR p;
376 ULONG Type;
377 OBJECT_ATTRIBUTES ObjectAttributes;
378 NTSTATUS Status;
379 HANDLE FileHandle;
380 IO_STATUS_BLOCK IoStatusBlock;
381 ULONG WaitPipeInfoSize;
382 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;
383
384 /* Start by making a unicode string of the name */
385 TRACE("Sent path: %S\n", lpNamedPipeName);
386 if (!RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName))
387 {
388 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
389 return FALSE;
390 }
391 NameLength = NamedPipeName.Length / sizeof(WCHAR);
392
393 /* All slashes must become backslashes */
394 for (i = 0; i < NameLength; i++)
395 {
396 /* Check and convert */
397 if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
398 }
399
400 /* Find the path type of the name we were given */
401 NewName = NamedPipeName;
402 Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);
403
404 /* Check if this was a device path, ie : "\\.\pipe\name" */
405 if (Type == RtlPathTypeLocalDevice)
406 {
407 /* Make sure it's a valid prefix */
408 RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
409 if (!RtlPrefixUnicodeString(&PipePrefix, &NewName, TRUE))
410 {
411 /* The name is invalid */
412 WARN("Invalid name!\n");
413 RtlFreeUnicodeString(&NamedPipeName);
414 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
415 return FALSE;
416 }
417
418 /* Move past it */
419 NewName.Buffer += PipePrefix.Length / sizeof(WCHAR);
420 NewName.Length -= PipePrefix.Length;
421 NewName.MaximumLength -= PipePrefix.Length;
422
423 /* Initialize the Dos Devices name */
424 TRACE("NewName: %wZ\n", &NewName);
425 RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
426 }
427 else if (Type == RtlPathTypeUncAbsolute)
428 {
429 /* The path is \\server\\pipe\name; find the pipename itself */
430 p = &NewName.Buffer[2];
431
432 /* First loop to get past the server name */
433 do
434 {
435 /* Check if this is a backslash */
436 if (*p == L'\\') break;
437
438 /* Check next */
439 p++;
440 } while (*p);
441
442 /* Now make sure the full name contains "pipe\" */
443 if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\") - sizeof(ANSI_NULL))))
444 {
445 /* Get to the pipe name itself now */
446 p += sizeof("pipe\\") - sizeof(ANSI_NULL);
447 }
448 else
449 {
450 /* The name is invalid */
451 WARN("Invalid name!\n");
452 RtlFreeUnicodeString(&NamedPipeName);
453 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
454 return FALSE;
455 }
456
457 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
458 }
459 else
460 {
461 WARN("Invalid path type\n");
462 RtlFreeUnicodeString(&NamedPipeName);
463 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
464 return FALSE;
465 }
466
467 /* Now calculate the total length of the structure and allocate it */
468 WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
469 NewName.Length;
470 WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
471 if (WaitPipeInfo == NULL)
472 {
473 RtlFreeUnicodeString(&NamedPipeName);
474 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
475 return FALSE;
476 }
477
478 /* Initialize the object attributes */
479 TRACE("Opening: %wZ\n", &DevicePath);
480 InitializeObjectAttributes(&ObjectAttributes,
481 &DevicePath,
482 OBJ_CASE_INSENSITIVE,
483 NULL,
484 NULL);
485
486 /* Open the path */
487 Status = NtOpenFile(&FileHandle,
488 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
489 &ObjectAttributes,
490 &IoStatusBlock,
491 FILE_SHARE_READ | FILE_SHARE_WRITE,
492 FILE_SYNCHRONOUS_IO_NONALERT);
493 if (!NT_SUCCESS(Status))
494 {
495 /* Fail; couldn't open */
496 WARN("Status: %lx\n", Status);
497 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
498 RtlFreeUnicodeString(&NamedPipeName);
499 BaseSetLastNTError(Status);
500 return FALSE;
501 }
502
503 /* Check what timeout we got */
504 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
505 {
506 /* Don't use a timeout */
507 WaitPipeInfo->TimeoutSpecified = FALSE;
508 }
509 else
510 {
511 /* Check if we should wait forever */
512 if (nTimeOut == NMPWAIT_WAIT_FOREVER)
513 {
514 /* Set the max */
515 WaitPipeInfo->Timeout.LowPart = 0;
516 WaitPipeInfo->Timeout.HighPart = 0x80000000;
517 }
518 else
519 {
520 /* Convert to NT format */
521 WaitPipeInfo->Timeout.QuadPart = nTimeOut * -10000LL;
522 }
523
524 /* In both cases, we do have a timeout */
525 WaitPipeInfo->TimeoutSpecified = TRUE;
526 }
527
528 /* Set the length and copy the name */
529 WaitPipeInfo->NameLength = NewName.Length;
530 RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);
531
532 /* Get rid of the full name */
533 RtlFreeUnicodeString(&NamedPipeName);
534
535 /* Let NPFS know of our request */
536 Status = NtFsControlFile(FileHandle,
537 NULL,
538 NULL,
539 NULL,
540 &IoStatusBlock,
541 FSCTL_PIPE_WAIT,
542 WaitPipeInfo,
543 WaitPipeInfoSize,
544 NULL,
545 0);
546
547 /* Free our pipe info data and close the handle */
548 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
549 NtClose(FileHandle);
550
551 /* Check the status */
552 if (!NT_SUCCESS(Status))
553 {
554 /* Failure to wait on the pipe */
555 WARN("Status: %lx\n", Status);
556 BaseSetLastNTError(Status);
557 return FALSE;
558 }
559
560 /* Success */
561 return TRUE;
562 }
563
564 /*
565 * @implemented
566 */
567 BOOL
568 WINAPI
569 ConnectNamedPipe(IN HANDLE hNamedPipe,
570 IN LPOVERLAPPED lpOverlapped)
571 {
572 NTSTATUS Status;
573
574 if (lpOverlapped != NULL)
575 {
576 PVOID ApcContext;
577
578 lpOverlapped->Internal = STATUS_PENDING;
579 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
580
581 Status = NtFsControlFile(hNamedPipe,
582 lpOverlapped->hEvent,
583 NULL,
584 ApcContext,
585 (PIO_STATUS_BLOCK)lpOverlapped,
586 FSCTL_PIPE_LISTEN,
587 NULL,
588 0,
589 NULL,
590 0);
591
592 /* return FALSE in case of failure and pending operations! */
593 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
594 {
595 BaseSetLastNTError(Status);
596 return FALSE;
597 }
598 }
599 else
600 {
601 IO_STATUS_BLOCK Iosb;
602
603 Status = NtFsControlFile(hNamedPipe,
604 NULL,
605 NULL,
606 NULL,
607 &Iosb,
608 FSCTL_PIPE_LISTEN,
609 NULL,
610 0,
611 NULL,
612 0);
613
614 /* wait in case operation is pending */
615 if (Status == STATUS_PENDING)
616 {
617 Status = NtWaitForSingleObject(hNamedPipe,
618 FALSE,
619 NULL);
620 if (NT_SUCCESS(Status))
621 {
622 Status = Iosb.Status;
623 }
624 }
625
626 if (!NT_SUCCESS(Status))
627 {
628 BaseSetLastNTError(Status);
629 return FALSE;
630 }
631 }
632
633 return TRUE;
634 }
635
636
637 /*
638 * @implemented
639 */
640 BOOL
641 WINAPI
642 SetNamedPipeHandleState(HANDLE hNamedPipe,
643 LPDWORD lpMode,
644 LPDWORD lpMaxCollectionCount,
645 LPDWORD lpCollectDataTimeout)
646 {
647 IO_STATUS_BLOCK Iosb;
648 NTSTATUS Status;
649
650 /* Check if the Mode is being changed */
651 if (lpMode)
652 {
653 FILE_PIPE_INFORMATION Settings;
654
655 /* Set the Completion Mode */
656 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
657 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
658
659 /* Set the Read Mode */
660 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
661 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
662
663 /* Send the changes to the Driver */
664 Status = NtSetInformationFile(hNamedPipe,
665 &Iosb,
666 &Settings,
667 sizeof(FILE_PIPE_INFORMATION),
668 FilePipeInformation);
669 if (!NT_SUCCESS(Status))
670 {
671 BaseSetLastNTError(Status);
672 return FALSE;
673 }
674 }
675
676 /* Check if the Collection count or Timeout are being changed */
677 if (lpMaxCollectionCount || lpCollectDataTimeout)
678 {
679 FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
680
681 /* Setting one without the other would delete it, so we read old one */
682 if (!lpMaxCollectionCount || !lpCollectDataTimeout)
683 {
684 Status = NtQueryInformationFile(hNamedPipe,
685 &Iosb,
686 &RemoteSettings,
687 sizeof(FILE_PIPE_REMOTE_INFORMATION),
688 FilePipeRemoteInformation);
689 if (!NT_SUCCESS(Status))
690 {
691 BaseSetLastNTError(Status);
692 return FALSE;
693 }
694 }
695
696 /* Now set the new settings */
697 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
698 *lpMaxCollectionCount :
699 RemoteSettings.MaximumCollectionCount;
700 if (lpCollectDataTimeout)
701 {
702 /* Convert it to Quad */
703 RemoteSettings.CollectDataTime.QuadPart = *lpCollectDataTimeout * -10000LL;
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 retrieve 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 */