- Make WaitNamedPipe (copied from the new implementation #ifdef USING_PROPER_NPFS_WAI...
[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 <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 /* Check what timeout we got */
502 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
503 {
504 /* Don't use a timeout */
505 WaitPipe.TimeoutSpecified = FALSE;
506 }
507 else
508 {
509 /* Check if we should wait forever */
510 if (nTimeOut == NMPWAIT_WAIT_FOREVER)
511 {
512 /* Set the max */
513 WaitPipe.Timeout.LowPart = 0;
514 WaitPipe.Timeout.HighPart = 0x80000000;
515 }
516 else
517 {
518 /* Convert to NT format */
519 WaitPipe.Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut);
520 }
521
522 /* In both cases, we do have a timeout */
523 WaitPipe.TimeoutSpecified = FALSE;
524 }
525
526 Status = NtFsControlFile(FileHandle,
527 NULL,
528 NULL,
529 NULL,
530 &Iosb,
531 FSCTL_PIPE_WAIT,
532 &WaitPipe,
533 sizeof(WaitPipe),
534 NULL,
535 0);
536 NtClose(FileHandle);
537 if (!NT_SUCCESS(Status))
538 {
539 SetLastErrorByStatus(Status);
540 return FALSE;
541 }
542
543 return TRUE;
544 }
545 #endif
546
547
548 /*
549 * @implemented
550 */
551 BOOL
552 WINAPI
553 ConnectNamedPipe(IN HANDLE hNamedPipe,
554 IN LPOVERLAPPED lpOverlapped)
555 {
556 NTSTATUS Status;
557
558 if (lpOverlapped != NULL)
559 {
560 PVOID ApcContext;
561
562 lpOverlapped->Internal = STATUS_PENDING;
563 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
564
565 Status = NtFsControlFile(hNamedPipe,
566 lpOverlapped->hEvent,
567 NULL,
568 ApcContext,
569 (PIO_STATUS_BLOCK)lpOverlapped,
570 FSCTL_PIPE_LISTEN,
571 NULL,
572 0,
573 NULL,
574 0);
575
576 /* return FALSE in case of failure and pending operations! */
577 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
578 {
579 SetLastErrorByStatus(Status);
580 return FALSE;
581 }
582 }
583 else
584 {
585 IO_STATUS_BLOCK Iosb;
586
587 Status = NtFsControlFile(hNamedPipe,
588 NULL,
589 NULL,
590 NULL,
591 &Iosb,
592 FSCTL_PIPE_LISTEN,
593 NULL,
594 0,
595 NULL,
596 0);
597
598 /* wait in case operation is pending */
599 if (Status == STATUS_PENDING)
600 {
601 Status = NtWaitForSingleObject(hNamedPipe,
602 FALSE,
603 NULL);
604 if (NT_SUCCESS(Status))
605 {
606 Status = Iosb.Status;
607 }
608 }
609
610 if (!NT_SUCCESS(Status))
611 {
612 SetLastErrorByStatus(Status);
613 return FALSE;
614 }
615 }
616
617 return TRUE;
618 }
619
620
621 /*
622 * @implemented
623 */
624 BOOL
625 WINAPI
626 SetNamedPipeHandleState(HANDLE hNamedPipe,
627 LPDWORD lpMode,
628 LPDWORD lpMaxCollectionCount,
629 LPDWORD lpCollectDataTimeout)
630 {
631 IO_STATUS_BLOCK Iosb;
632 NTSTATUS Status;
633
634 /* Check if the Mode is being changed */
635 if (lpMode)
636 {
637 FILE_PIPE_INFORMATION Settings;
638
639 /* Set the Completion Mode */
640 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
641 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
642
643 /* Set the Read Mode */
644 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
645 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
646
647 /* Send the changes to the Driver */
648 Status = NtSetInformationFile(hNamedPipe,
649 &Iosb,
650 &Settings,
651 sizeof(FILE_PIPE_INFORMATION),
652 FilePipeInformation);
653 if (!NT_SUCCESS(Status))
654 {
655 SetLastErrorByStatus(Status);
656 return FALSE;
657 }
658 }
659
660 /* Check if the Collection count or Timeout are being changed */
661 if (lpMaxCollectionCount || lpCollectDataTimeout)
662 {
663 FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
664
665 /* Setting one without the other would delete it, so we read old one */
666 if (!lpMaxCollectionCount || !lpCollectDataTimeout)
667 {
668 Status = NtQueryInformationFile(hNamedPipe,
669 &Iosb,
670 &RemoteSettings,
671 sizeof(FILE_PIPE_REMOTE_INFORMATION),
672 FilePipeRemoteInformation);
673 if (!NT_SUCCESS(Status))
674 {
675 SetLastErrorByStatus(Status);
676 return FALSE;
677 }
678 }
679
680 /* Now set the new settings */
681 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
682 *lpMaxCollectionCount :
683 RemoteSettings.MaximumCollectionCount;
684 if (lpCollectDataTimeout)
685 {
686 /* Convert it to Quad */
687 RemoteSettings.CollectDataTime.QuadPart =
688 -(LONGLONG)UInt32x32To64(10000, *lpCollectDataTimeout);
689 }
690
691 /* Tell the driver to change them */
692 Status = NtSetInformationFile(hNamedPipe,
693 &Iosb,
694 &RemoteSettings,
695 sizeof(FILE_PIPE_REMOTE_INFORMATION),
696 FilePipeRemoteInformation);
697 if (!NT_SUCCESS(Status))
698 {
699 SetLastErrorByStatus(Status);
700 return FALSE;
701 }
702 }
703
704 return TRUE;
705 }
706
707
708 /*
709 * @implemented
710 */
711 BOOL
712 WINAPI
713 CallNamedPipeA(LPCSTR lpNamedPipeName,
714 LPVOID lpInBuffer,
715 DWORD nInBufferSize,
716 LPVOID lpOutBuffer,
717 DWORD nOutBufferSize,
718 LPDWORD lpBytesRead,
719 DWORD nTimeOut)
720 {
721 PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
722 ANSI_STRING AnsiPipe;
723
724 /* Initialize the string as ANSI_STRING and convert to Unicode */
725 RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName);
726 RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE);
727
728 /* Call the Unicode function */
729 return CallNamedPipeW(PipeName->Buffer,
730 lpInBuffer,
731 nInBufferSize,
732 lpOutBuffer,
733 nOutBufferSize,
734 lpBytesRead,
735 nTimeOut);
736 }
737
738
739 /*
740 * @implemented
741 */
742 BOOL
743 WINAPI
744 CallNamedPipeW(LPCWSTR lpNamedPipeName,
745 LPVOID lpInBuffer,
746 DWORD nInBufferSize,
747 LPVOID lpOutBuffer,
748 DWORD nOutBufferSize,
749 LPDWORD lpBytesRead,
750 DWORD nTimeOut)
751 {
752 HANDLE hPipe;
753 BOOL bRetry = TRUE;
754 BOOL bError;
755 DWORD dwPipeMode;
756
757 while (TRUE)
758 {
759 /* Try creating it */
760 hPipe = CreateFileW(lpNamedPipeName,
761 GENERIC_READ | GENERIC_WRITE,
762 FILE_SHARE_READ | FILE_SHARE_WRITE,
763 NULL,
764 OPEN_EXISTING,
765 FILE_ATTRIBUTE_NORMAL,
766 NULL);
767
768 /* Success, break out */
769 if (hPipe != INVALID_HANDLE_VALUE)
770 break;
771
772 /* Already tried twice, give up */
773 if (bRetry == FALSE)
774 return FALSE;
775
776 /* Wait on it */
777 WaitNamedPipeW(lpNamedPipeName, nTimeOut);
778
779 /* Get ready to try again */
780 bRetry = FALSE;
781 }
782
783 /* Set the pipe mode */
784 dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
785 bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL);
786 if (!bError)
787 {
788 /* Couldn't change state, fail */
789 CloseHandle(hPipe);
790 return FALSE;
791 }
792
793 /* Do the transact */
794 bError = TransactNamedPipe(hPipe,
795 lpInBuffer,
796 nInBufferSize,
797 lpOutBuffer,
798 nOutBufferSize,
799 lpBytesRead,
800 NULL);
801
802 /* Close the handle */
803 CloseHandle(hPipe);
804
805 return bError;
806 }
807
808
809 /*
810 * @implemented
811 */
812 BOOL
813 WINAPI
814 DisconnectNamedPipe(HANDLE hNamedPipe)
815 {
816 IO_STATUS_BLOCK Iosb;
817 NTSTATUS Status;
818
819 /* Send the FSCTL to the driver */
820 Status = NtFsControlFile(hNamedPipe,
821 NULL,
822 NULL,
823 NULL,
824 &Iosb,
825 FSCTL_PIPE_DISCONNECT,
826 NULL,
827 0,
828 NULL,
829 0);
830 if (Status == STATUS_PENDING)
831 {
832 /* Wait on NPFS to finish and get updated status */
833 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
834 if (NT_SUCCESS(Status))
835 Status = Iosb.Status;
836 }
837
838 /* Check for error */
839 if (!NT_SUCCESS(Status))
840 {
841 /* Fail */
842 SetLastErrorByStatus(Status);
843 return FALSE;
844 }
845
846 return TRUE;
847 }
848
849
850 /*
851 * @unimplemented
852 */
853 BOOL
854 WINAPI
855 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
856 LPDWORD lpState,
857 LPDWORD lpCurInstances,
858 LPDWORD lpMaxCollectionCount,
859 LPDWORD lpCollectDataTimeout,
860 LPWSTR lpUserName,
861 DWORD nMaxUserNameSize)
862 {
863 IO_STATUS_BLOCK StatusBlock;
864 NTSTATUS Status;
865
866 if (lpState != NULL)
867 {
868 FILE_PIPE_INFORMATION PipeInfo;
869
870 Status = NtQueryInformationFile(hNamedPipe,
871 &StatusBlock,
872 &PipeInfo,
873 sizeof(FILE_PIPE_INFORMATION),
874 FilePipeInformation);
875 if (!NT_SUCCESS(Status))
876 {
877 SetLastErrorByStatus(Status);
878 return FALSE;
879 }
880
881 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
882 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
883 }
884
885 if(lpCurInstances != NULL)
886 {
887 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
888
889 Status = NtQueryInformationFile(hNamedPipe,
890 &StatusBlock,
891 &LocalInfo,
892 sizeof(FILE_PIPE_LOCAL_INFORMATION),
893 FilePipeLocalInformation);
894 if (!NT_SUCCESS(Status))
895 {
896 SetLastErrorByStatus(Status);
897 return FALSE;
898 }
899
900 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
901 }
902
903 if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
904 {
905 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
906
907 Status = NtQueryInformationFile(hNamedPipe,
908 &StatusBlock,
909 &RemoteInfo,
910 sizeof(FILE_PIPE_REMOTE_INFORMATION),
911 FilePipeRemoteInformation);
912 if (!NT_SUCCESS(Status))
913 {
914 SetLastErrorByStatus(Status);
915 return FALSE;
916 }
917
918 if (lpMaxCollectionCount != NULL)
919 {
920 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
921 }
922
923 if(lpCollectDataTimeout != NULL)
924 {
925 /* FIXME */
926 *lpCollectDataTimeout = 0;
927 }
928 }
929
930 if (lpUserName != NULL)
931 {
932 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
933 retreive the user name with GetUserName(), revert the impersonation
934 and finally restore the thread token */
935 }
936
937 return TRUE;
938 }
939
940
941 /*
942 * @implemented
943 */
944 BOOL
945 WINAPI
946 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
947 LPDWORD lpState,
948 LPDWORD lpCurInstances,
949 LPDWORD lpMaxCollectionCount,
950 LPDWORD lpCollectDataTimeout,
951 LPSTR lpUserName,
952 DWORD nMaxUserNameSize)
953 {
954 UNICODE_STRING UserNameW = {0};
955 ANSI_STRING UserNameA;
956 BOOL Ret;
957
958 if(lpUserName != NULL)
959 {
960 UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR);
961 UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength);
962 if (UserNameW.Buffer == NULL)
963 {
964 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
965 return FALSE;
966 }
967
968 UserNameA.Buffer = lpUserName;
969 UserNameA.Length = 0;
970 UserNameA.MaximumLength = (USHORT)nMaxUserNameSize;
971 }
972
973 Ret = GetNamedPipeHandleStateW(hNamedPipe,
974 lpState,
975 lpCurInstances,
976 lpMaxCollectionCount,
977 lpCollectDataTimeout,
978 UserNameW.Buffer,
979 nMaxUserNameSize);
980 if (Ret && lpUserName != NULL)
981 {
982 NTSTATUS Status;
983
984 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
985 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
986 if (!NT_SUCCESS(Status))
987 {
988 SetLastErrorByStatus(Status);
989 Ret = FALSE;
990 }
991 }
992
993 if (UserNameW.Buffer != NULL)
994 {
995 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
996 }
997
998 return Ret;
999 }
1000
1001
1002 /*
1003 * @implemented
1004 */
1005 BOOL
1006 WINAPI
1007 GetNamedPipeInfo(HANDLE hNamedPipe,
1008 LPDWORD lpFlags,
1009 LPDWORD lpOutBufferSize,
1010 LPDWORD lpInBufferSize,
1011 LPDWORD lpMaxInstances)
1012 {
1013 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
1014 IO_STATUS_BLOCK StatusBlock;
1015 NTSTATUS Status;
1016
1017 Status = NtQueryInformationFile(hNamedPipe,
1018 &StatusBlock,
1019 &PipeLocalInformation,
1020 sizeof(FILE_PIPE_LOCAL_INFORMATION),
1021 FilePipeLocalInformation);
1022 if (!NT_SUCCESS(Status))
1023 {
1024 SetLastErrorByStatus(Status);
1025 return FALSE;
1026 }
1027
1028 if (lpFlags != NULL)
1029 {
1030 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
1031 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
1032 }
1033
1034 if (lpOutBufferSize != NULL)
1035 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
1036
1037 if (lpInBufferSize != NULL)
1038 *lpInBufferSize = PipeLocalInformation.InboundQuota;
1039
1040 if (lpMaxInstances != NULL)
1041 {
1042 if (PipeLocalInformation.MaximumInstances >= 255)
1043 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
1044 else
1045 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
1046 }
1047
1048 return TRUE;
1049 }
1050
1051
1052 /*
1053 * @implemented
1054 */
1055 BOOL
1056 WINAPI
1057 PeekNamedPipe(HANDLE hNamedPipe,
1058 LPVOID lpBuffer,
1059 DWORD nBufferSize,
1060 LPDWORD lpBytesRead,
1061 LPDWORD lpTotalBytesAvail,
1062 LPDWORD lpBytesLeftThisMessage)
1063 {
1064 PFILE_PIPE_PEEK_BUFFER Buffer;
1065 IO_STATUS_BLOCK Iosb;
1066 ULONG BufferSize;
1067 ULONG BytesRead;
1068 NTSTATUS Status;
1069
1070 /* Calculate the buffer space that we'll need and allocate it */
1071 BufferSize = nBufferSize + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
1072 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1073 if (Buffer == NULL)
1074 {
1075 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1076 return FALSE;
1077 }
1078
1079 /* Tell the driver to seek */
1080 Status = NtFsControlFile(hNamedPipe,
1081 NULL,
1082 NULL,
1083 NULL,
1084 &Iosb,
1085 FSCTL_PIPE_PEEK,
1086 NULL,
1087 0,
1088 Buffer,
1089 BufferSize);
1090 if (Status == STATUS_PENDING)
1091 {
1092 /* Wait for npfs to be done, and update the status */
1093 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
1094 if (NT_SUCCESS(Status))
1095 Status = Iosb.Status;
1096 }
1097
1098 /* Overflow is success for us */
1099 if (Status == STATUS_BUFFER_OVERFLOW)
1100 Status = STATUS_SUCCESS;
1101
1102 /* If we failed */
1103 if (!NT_SUCCESS(Status))
1104 {
1105 /* Free the buffer and return failure */
1106 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1107 SetLastErrorByStatus(Status);
1108 return FALSE;
1109 }
1110
1111 /* Check if caller requested bytes available */
1112 if (lpTotalBytesAvail)
1113 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1114
1115 /* Calculate the bytes returned, minus our structure overhead */
1116 BytesRead = (ULONG)(Iosb.Information -
1117 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1118
1119 /* Check if caller requested bytes read */
1120 if (lpBytesRead)
1121 {
1122 /* Return the bytes read */
1123 *lpBytesRead = BytesRead;
1124 }
1125
1126 /* Check if caller requested bytes left */
1127 if (lpBytesLeftThisMessage)
1128 {
1129 /* Calculate total minus what we returned and our structure overhead */
1130 *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead;
1131 }
1132
1133 /* Check if the caller wanted to see the actual data */
1134 if (lpBuffer)
1135 {
1136 /* Give him what he wants */
1137 RtlCopyMemory(lpBuffer,
1138 Buffer->Data,
1139 BytesRead);
1140 }
1141
1142 /* Free the buffer */
1143 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1144
1145 return TRUE;
1146 }
1147
1148
1149 /*
1150 * @implemented
1151 */
1152 BOOL
1153 WINAPI
1154 TransactNamedPipe(IN HANDLE hNamedPipe,
1155 IN LPVOID lpInBuffer,
1156 IN DWORD nInBufferSize,
1157 OUT LPVOID lpOutBuffer,
1158 IN DWORD nOutBufferSize,
1159 OUT LPDWORD lpBytesRead OPTIONAL,
1160 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1161 {
1162 NTSTATUS Status;
1163
1164 if (lpBytesRead != NULL)
1165 {
1166 *lpBytesRead = 0;
1167 }
1168
1169 if (lpOverlapped != NULL)
1170 {
1171 PVOID ApcContext;
1172
1173 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1174 lpOverlapped->Internal = STATUS_PENDING;
1175
1176 Status = NtFsControlFile(hNamedPipe,
1177 lpOverlapped->hEvent,
1178 NULL,
1179 ApcContext,
1180 (PIO_STATUS_BLOCK)lpOverlapped,
1181 FSCTL_PIPE_TRANSCEIVE,
1182 lpInBuffer,
1183 nInBufferSize,
1184 lpOutBuffer,
1185 nOutBufferSize);
1186 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1187 {
1188 SetLastErrorByStatus(Status);
1189 return FALSE;
1190 }
1191
1192 if (lpBytesRead != NULL)
1193 {
1194 *lpBytesRead = lpOverlapped->InternalHigh;
1195 }
1196 }
1197 else
1198 {
1199 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1200 IO_STATUS_BLOCK Iosb;
1201
1202 Status = NtFsControlFile(hNamedPipe,
1203 NULL,
1204 NULL,
1205 NULL,
1206 &Iosb,
1207 FSCTL_PIPE_TRANSCEIVE,
1208 lpInBuffer,
1209 nInBufferSize,
1210 lpOutBuffer,
1211 nOutBufferSize);
1212 if (Status == STATUS_PENDING)
1213 {
1214 Status = NtWaitForSingleObject(hNamedPipe,
1215 FALSE,
1216 NULL);
1217 if (NT_SUCCESS(Status))
1218 Status = Iosb.Status;
1219 }
1220
1221 if (NT_SUCCESS(Status))
1222 {
1223 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1224 check that case either and crashes (only after the operation
1225 completed) */
1226 *lpBytesRead = Iosb.Information;
1227 }
1228 else
1229 {
1230 SetLastErrorByStatus(Status);
1231 return FALSE;
1232 }
1233 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1234 DWORD nActualBytes;
1235
1236 while (0 != nInBufferSize &&
1237 WriteFile(hNamedPipe, lpInBuffer, nInBufferSize, &nActualBytes,
1238 NULL))
1239 {
1240 lpInBuffer = (LPVOID)((char *) lpInBuffer + nActualBytes);
1241 nInBufferSize -= nActualBytes;
1242 }
1243
1244 if (0 != nInBufferSize)
1245 {
1246 /* Must have dropped out of the while 'cause WriteFile failed */
1247 return FALSE;
1248 }
1249
1250 if (!ReadFile(hNamedPipe, lpOutBuffer, nOutBufferSize, &nActualBytes,
1251 NULL))
1252 {
1253 return FALSE;
1254 }
1255
1256 if (NULL != lpBytesRead)
1257 {
1258 *lpBytesRead = nActualBytes;
1259 }
1260 #endif
1261 }
1262
1263 return TRUE;
1264 }
1265
1266 /* EOF */