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