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