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