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