Fix a handle leak.
[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
928 UserNameA.Buffer = lpUserName;
929 UserNameA.Length = 0;
930 UserNameA.MaximumLength = nMaxUserNameSize;
931 }
932
933 Ret = GetNamedPipeHandleStateW(hNamedPipe,
934 lpState,
935 lpCurInstances,
936 lpMaxCollectionCount,
937 lpCollectDataTimeout,
938 UserNameW.Buffer,
939 nMaxUserNameSize);
940
941 if(Ret && lpUserName != NULL)
942 {
943 NTSTATUS Status;
944
945 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
946 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
947 if(!NT_SUCCESS(Status))
948 {
949 SetLastErrorByStatus(Status);
950 Ret = FALSE;
951 }
952 }
953
954 if(UserNameW.Buffer != NULL)
955 {
956 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
957 }
958
959 return Ret;
960 }
961
962
963 /*
964 * @implemented
965 */
966 BOOL STDCALL
967 GetNamedPipeInfo(HANDLE hNamedPipe,
968 LPDWORD lpFlags,
969 LPDWORD lpOutBufferSize,
970 LPDWORD lpInBufferSize,
971 LPDWORD lpMaxInstances)
972 {
973 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
974 IO_STATUS_BLOCK StatusBlock;
975 NTSTATUS Status;
976
977 Status = NtQueryInformationFile(hNamedPipe,
978 &StatusBlock,
979 &PipeLocalInformation,
980 sizeof(FILE_PIPE_LOCAL_INFORMATION),
981 FilePipeLocalInformation);
982 if (!NT_SUCCESS(Status))
983 {
984 SetLastErrorByStatus(Status);
985 return(FALSE);
986 }
987
988 if (lpFlags != NULL)
989 {
990 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
991 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
992 }
993
994 if (lpOutBufferSize != NULL)
995 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
996
997 if (lpInBufferSize != NULL)
998 *lpInBufferSize = PipeLocalInformation.InboundQuota;
999
1000 if (lpMaxInstances != NULL)
1001 {
1002 if (PipeLocalInformation.MaximumInstances >= 255)
1003 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
1004 else
1005 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
1006 }
1007
1008 return(TRUE);
1009 }
1010
1011 /*
1012 * @implemented
1013 */
1014 BOOL
1015 WINAPI
1016 PeekNamedPipe(HANDLE hNamedPipe,
1017 LPVOID lpBuffer,
1018 DWORD nBufferSize,
1019 LPDWORD lpBytesRead,
1020 LPDWORD lpTotalBytesAvail,
1021 LPDWORD lpBytesLeftThisMessage)
1022 {
1023 PFILE_PIPE_PEEK_BUFFER Buffer;
1024 IO_STATUS_BLOCK Iosb;
1025 ULONG BufferSize;
1026 NTSTATUS Status;
1027
1028 /* Calculate the buffer space that we'll need and allocate it */
1029 BufferSize = nBufferSize + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
1030 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
1031 if (Buffer == NULL)
1032 {
1033 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1034 return FALSE;
1035 }
1036
1037 /* Tell the driver to seek */
1038 Status = NtFsControlFile(hNamedPipe,
1039 NULL,
1040 NULL,
1041 NULL,
1042 &Iosb,
1043 FSCTL_PIPE_PEEK,
1044 NULL,
1045 0,
1046 Buffer,
1047 BufferSize);
1048 if (Status == STATUS_PENDING)
1049 {
1050 /* Wait for npfs to be done, and update the status */
1051 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
1052 if (NT_SUCCESS(Status)) Status = Iosb.Status;
1053 }
1054
1055 /* Overflow is success for us */
1056 if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_SUCCESS;
1057
1058 /* If we failed */
1059 if (!NT_SUCCESS(Status))
1060 {
1061 /* Free the buffer and return failure */
1062 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1063 SetLastErrorByStatus(Status);
1064 return FALSE;
1065 }
1066
1067 /* Check if caller requested bytes available */
1068 if (lpTotalBytesAvail) *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1069
1070 /* Check if caller requested bytes read */
1071 if (lpBytesRead)
1072 {
1073 /* Calculate the bytes returned, minus our structure overhead */
1074 *lpBytesRead = (ULONG)(Iosb.Information -
1075 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1076 }
1077
1078 /* Check if caller requested bytes left */
1079 if (lpBytesLeftThisMessage)
1080 {
1081 /* Calculate total minus what we returned and our structure overhead */
1082 *lpBytesLeftThisMessage = Buffer->MessageLength -
1083 (ULONG)(Iosb.Information -
1084 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1085 }
1086
1087 /* Check if the caller wanted to see the actual data */
1088 if (lpBuffer)
1089 {
1090 /* Give him what he wants */
1091 RtlCopyMemory(lpBuffer,
1092 Buffer->Data,
1093 Iosb.Information -
1094 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1095 }
1096
1097 /* Free the buffer and return success */
1098 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1099 return TRUE;
1100 }
1101
1102 /*
1103 * @implemented
1104 */
1105 BOOL STDCALL
1106 TransactNamedPipe(IN HANDLE hNamedPipe,
1107 IN LPVOID lpInBuffer,
1108 IN DWORD nInBufferSize,
1109 OUT LPVOID lpOutBuffer,
1110 IN DWORD nOutBufferSize,
1111 OUT LPDWORD lpBytesRead OPTIONAL,
1112 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1113 {
1114 NTSTATUS Status;
1115
1116 if (lpBytesRead != NULL)
1117 {
1118 *lpBytesRead = 0;
1119 }
1120
1121 if (lpOverlapped != NULL)
1122 {
1123 PVOID ApcContext;
1124
1125 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1126 lpOverlapped->Internal = STATUS_PENDING;
1127
1128 Status = NtFsControlFile(hNamedPipe,
1129 lpOverlapped->hEvent,
1130 NULL,
1131 ApcContext,
1132 (PIO_STATUS_BLOCK)lpOverlapped,
1133 FSCTL_PIPE_TRANSCEIVE,
1134 lpInBuffer,
1135 nInBufferSize,
1136 lpOutBuffer,
1137 nOutBufferSize);
1138
1139 /* return FALSE in case of failure and pending operations! */
1140 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1141 {
1142 SetLastErrorByStatus(Status);
1143 return FALSE;
1144 }
1145
1146 if (lpBytesRead != NULL)
1147 {
1148 *lpBytesRead = lpOverlapped->InternalHigh;
1149 }
1150 }
1151 else
1152 {
1153 IO_STATUS_BLOCK Iosb;
1154
1155 Status = NtFsControlFile(hNamedPipe,
1156 NULL,
1157 NULL,
1158 NULL,
1159 &Iosb,
1160 FSCTL_PIPE_TRANSCEIVE,
1161 lpInBuffer,
1162 nInBufferSize,
1163 lpOutBuffer,
1164 nOutBufferSize);
1165
1166 /* wait in case operation is pending */
1167 if (Status == STATUS_PENDING)
1168 {
1169 Status = NtWaitForSingleObject(hNamedPipe,
1170 FALSE,
1171 NULL);
1172 if (NT_SUCCESS(Status))
1173 {
1174 Status = Iosb.Status;
1175 }
1176 }
1177
1178 if (NT_SUCCESS(Status))
1179 {
1180 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1181 check that case either and crashes (only after the operation
1182 completed) */
1183 *lpBytesRead = Iosb.Information;
1184 }
1185 else
1186 {
1187 SetLastErrorByStatus(Status);
1188 return FALSE;
1189 }
1190 }
1191
1192 return TRUE;
1193 }
1194
1195 /* EOF */