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