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