d464992c8f5ec074d16a4962e3a1d3e8b9a4121c
[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 #include "../include/debug.h"
17
18 /* FIXME - defined in ntifs.h */
19 #if !defined(FILE_PIPE_BYTE_STREAM_TYPE) && !defined(FILE_PIPE_MESSAGE_TYPE)
20 #define FILE_PIPE_BYTE_STREAM_TYPE 0x00000000
21 #define FILE_PIPE_MESSAGE_TYPE 0x00000001
22 #endif
23
24 /* FUNCTIONS ****************************************************************/
25
26 /*
27 * @implemented
28 */
29 HANDLE STDCALL
30 CreateNamedPipeA(LPCSTR lpName,
31 DWORD dwOpenMode,
32 DWORD dwPipeMode,
33 DWORD nMaxInstances,
34 DWORD nOutBufferSize,
35 DWORD nInBufferSize,
36 DWORD nDefaultTimeOut,
37 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
38 {
39 HANDLE NamedPipeHandle;
40 UNICODE_STRING NameU;
41 ANSI_STRING NameA;
42
43 RtlInitAnsiString(&NameA, (LPSTR)lpName);
44 RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
45
46 NamedPipeHandle = CreateNamedPipeW(NameU.Buffer,
47 dwOpenMode,
48 dwPipeMode,
49 nMaxInstances,
50 nOutBufferSize,
51 nInBufferSize,
52 nDefaultTimeOut,
53 lpSecurityAttributes);
54
55 RtlFreeUnicodeString(&NameU);
56
57 return(NamedPipeHandle);
58 }
59
60
61 /*
62 * @implemented
63 */
64 HANDLE STDCALL
65 CreateNamedPipeW(LPCWSTR lpName,
66 DWORD dwOpenMode,
67 DWORD dwPipeMode,
68 DWORD nMaxInstances,
69 DWORD nOutBufferSize,
70 DWORD nInBufferSize,
71 DWORD nDefaultTimeOut,
72 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
73 {
74 UNICODE_STRING NamedPipeName;
75 BOOL Result;
76 NTSTATUS Status;
77 OBJECT_ATTRIBUTES ObjectAttributes;
78 HANDLE PipeHandle;
79 ACCESS_MASK DesiredAccess;
80 ULONG CreateOptions;
81 ULONG WriteModeMessage;
82 ULONG ReadModeMessage;
83 ULONG NonBlocking;
84 IO_STATUS_BLOCK Iosb;
85 ULONG ShareAccess, Attributes;
86 LARGE_INTEGER DefaultTimeOut;
87 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
88
89 if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
90 {
91 SetLastError(ERROR_INVALID_PARAMETER);
92 return INVALID_HANDLE_VALUE;
93 }
94
95 Result = RtlDosPathNameToNtPathName_U((LPWSTR)lpName,
96 &NamedPipeName,
97 NULL,
98 NULL);
99 if (!Result)
100 {
101 SetLastError(ERROR_PATH_NOT_FOUND);
102 return(INVALID_HANDLE_VALUE);
103 }
104
105 DPRINT("Pipe name: %wZ\n", &NamedPipeName);
106 DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
107
108 Attributes = OBJ_CASE_INSENSITIVE;
109 if(lpSecurityAttributes)
110 {
111 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
112 if(lpSecurityAttributes->bInheritHandle)
113 Attributes |= OBJ_INHERIT;
114 }
115
116 InitializeObjectAttributes(&ObjectAttributes,
117 &NamedPipeName,
118 Attributes,
119 NULL,
120 SecurityDescriptor);
121
122 DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY));
123 ShareAccess = 0;
124 CreateOptions = 0;
125
126 if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
127 CreateOptions |= FILE_WRITE_THROUGH;
128 if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
129 CreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
130
131 if (dwOpenMode & PIPE_ACCESS_INBOUND)
132 {
133 ShareAccess |= FILE_SHARE_WRITE;
134 DesiredAccess |= GENERIC_READ;
135 }
136 if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
137 {
138 ShareAccess |= FILE_SHARE_READ;
139 DesiredAccess |= GENERIC_WRITE;
140 }
141
142 if (dwPipeMode & PIPE_TYPE_MESSAGE)
143 WriteModeMessage = FILE_PIPE_MESSAGE_TYPE;
144 else
145 WriteModeMessage = FILE_PIPE_BYTE_STREAM_TYPE;
146
147 if (dwPipeMode & PIPE_READMODE_MESSAGE)
148 ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
149 else
150 ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
151
152 if (dwPipeMode & PIPE_NOWAIT)
153 NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
154 else
155 NonBlocking = FILE_PIPE_QUEUE_OPERATION;
156
157 DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000LL;
158
159 Status = NtCreateNamedPipeFile(&PipeHandle,
160 DesiredAccess,
161 &ObjectAttributes,
162 &Iosb,
163 ShareAccess,
164 FILE_OPEN_IF,
165 CreateOptions,
166 WriteModeMessage,
167 ReadModeMessage,
168 NonBlocking,
169 nMaxInstances,
170 nInBufferSize,
171 nOutBufferSize,
172 &DefaultTimeOut);
173
174 RtlFreeUnicodeString(&NamedPipeName);
175
176 if (!NT_SUCCESS(Status))
177 {
178 DPRINT("NtCreateNamedPipe failed (Status %x)!\n", Status);
179 SetLastErrorByStatus (Status);
180 return INVALID_HANDLE_VALUE;
181 }
182
183 return PipeHandle;
184 }
185
186
187 /*
188 * @implemented
189 */
190 BOOL STDCALL
191 WaitNamedPipeA(LPCSTR lpNamedPipeName,
192 DWORD nTimeOut)
193 {
194 BOOL r;
195 UNICODE_STRING NameU;
196 ANSI_STRING NameA;
197
198 RtlInitAnsiString(&NameA, (LPSTR)lpNamedPipeName);
199 RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
200
201 r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
202
203 RtlFreeUnicodeString(&NameU);
204
205 return(r);
206 }
207
208
209 /*
210 * @implemented
211 */
212 BOOL STDCALL
213 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
214 DWORD nTimeOut)
215 {
216 UNICODE_STRING NamedPipeName;
217 BOOL r;
218 NTSTATUS Status;
219 OBJECT_ATTRIBUTES ObjectAttributes;
220 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe;
221 HANDLE FileHandle;
222 IO_STATUS_BLOCK Iosb;
223
224 r = RtlDosPathNameToNtPathName_U((LPWSTR)lpNamedPipeName,
225 &NamedPipeName,
226 NULL,
227 NULL);
228 if (!r)
229 {
230 return(FALSE);
231 }
232
233 InitializeObjectAttributes(&ObjectAttributes,
234 &NamedPipeName,
235 OBJ_CASE_INSENSITIVE,
236 NULL,
237 NULL);
238 Status = NtOpenFile(&FileHandle,
239 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
240 &ObjectAttributes,
241 &Iosb,
242 FILE_SHARE_READ | FILE_SHARE_WRITE,
243 FILE_SYNCHRONOUS_IO_NONALERT);
244 if (!NT_SUCCESS(Status))
245 {
246 SetLastErrorByStatus (Status);
247 return(FALSE);
248 }
249
250 WaitPipe.Timeout.QuadPart = nTimeOut * -10000LL;
251
252 Status = NtFsControlFile(FileHandle,
253 NULL,
254 NULL,
255 NULL,
256 &Iosb,
257 FSCTL_PIPE_WAIT,
258 &WaitPipe,
259 sizeof(WaitPipe),
260 NULL,
261 0);
262 NtClose(FileHandle);
263 if (!NT_SUCCESS(Status))
264 {
265 SetLastErrorByStatus (Status);
266 return(FALSE);
267 }
268
269 return(TRUE);
270 }
271
272
273 /*
274 * @implemented
275 */
276 BOOL STDCALL
277 ConnectNamedPipe(IN HANDLE hNamedPipe,
278 IN LPOVERLAPPED lpOverlapped)
279 {
280 NTSTATUS Status;
281
282 if (lpOverlapped != NULL)
283 {
284 PVOID ApcContext;
285
286 lpOverlapped->Internal = STATUS_PENDING;
287 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
288
289 Status = NtFsControlFile(hNamedPipe,
290 lpOverlapped->hEvent,
291 NULL,
292 ApcContext,
293 (PIO_STATUS_BLOCK)lpOverlapped,
294 FSCTL_PIPE_LISTEN,
295 NULL,
296 0,
297 NULL,
298 0);
299
300 /* return FALSE in case of failure and pending operations! */
301 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
302 {
303 SetLastErrorByStatus(Status);
304 return FALSE;
305 }
306 }
307 else
308 {
309 IO_STATUS_BLOCK Iosb;
310
311 Status = NtFsControlFile(hNamedPipe,
312 NULL,
313 NULL,
314 NULL,
315 &Iosb,
316 FSCTL_PIPE_LISTEN,
317 NULL,
318 0,
319 NULL,
320 0);
321
322 /* wait in case operation is pending */
323 if (Status == STATUS_PENDING)
324 {
325 Status = NtWaitForSingleObject(hNamedPipe,
326 FALSE,
327 NULL);
328 if (NT_SUCCESS(Status))
329 {
330 Status = Iosb.Status;
331 }
332 }
333
334 if (!NT_SUCCESS(Status))
335 {
336 SetLastErrorByStatus(Status);
337 return FALSE;
338 }
339 }
340
341 return TRUE;
342 }
343
344
345 /*
346 * @implemented
347 */
348 BOOL
349 STDCALL
350 SetNamedPipeHandleState(HANDLE hNamedPipe,
351 LPDWORD lpMode,
352 LPDWORD lpMaxCollectionCount,
353 LPDWORD lpCollectDataTimeout)
354 {
355 IO_STATUS_BLOCK Iosb;
356 NTSTATUS Status;
357
358 /* Check if the Mode is being changed */
359 if (lpMode)
360 {
361 FILE_PIPE_INFORMATION Settings;
362
363 /* Set the Completion Mode */
364 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ?
365 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION;
366
367 /* Set the Read Mode */
368 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ?
369 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE;
370
371 /* Send the changes to the Driver */
372 Status = NtSetInformationFile(hNamedPipe,
373 &Iosb,
374 &Settings,
375 sizeof(FILE_PIPE_INFORMATION),
376 FilePipeInformation);
377 if (!NT_SUCCESS(Status))
378 {
379 SetLastErrorByStatus(Status);
380 return(FALSE);
381 }
382 }
383
384 /* Check if the Collection count or Timeout are being changed */
385 if (lpMaxCollectionCount || lpCollectDataTimeout)
386 {
387 FILE_PIPE_REMOTE_INFORMATION RemoteSettings;
388
389 /* Setting one without the other would delete it, so we read old one */
390 if (!lpMaxCollectionCount || !lpCollectDataTimeout)
391 {
392 Status = NtQueryInformationFile(hNamedPipe,
393 &Iosb,
394 &RemoteSettings,
395 sizeof(FILE_PIPE_REMOTE_INFORMATION),
396 FilePipeRemoteInformation);
397
398 if (!NT_SUCCESS(Status))
399 {
400 SetLastErrorByStatus(Status);
401 return(FALSE);
402 }
403 }
404
405 /* Now set the new settings */
406 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
407 *lpMaxCollectionCount :
408 RemoteSettings.MaximumCollectionCount;
409 if (lpCollectDataTimeout)
410 {
411 /* Convert it to Quad */
412 RemoteSettings.CollectDataTime.QuadPart = -(LONGLONG)
413 UInt32x32To64(10000,
414 *lpCollectDataTimeout);
415 }
416
417 /* Tell the driver to change them */
418 Status = NtSetInformationFile(hNamedPipe,
419 &Iosb,
420 &RemoteSettings,
421 sizeof(FILE_PIPE_REMOTE_INFORMATION),
422 FilePipeRemoteInformation);
423
424 if (!NT_SUCCESS(Status))
425 {
426 SetLastErrorByStatus(Status);
427 return(FALSE);
428 }
429 }
430
431 /* All done */
432 return TRUE;
433 }
434
435 /*
436 * @implemented
437 */
438 BOOL STDCALL
439 CallNamedPipeA(LPCSTR lpNamedPipeName,
440 LPVOID lpInBuffer,
441 DWORD nInBufferSize,
442 LPVOID lpOutBuffer,
443 DWORD nOutBufferSize,
444 LPDWORD lpBytesRead,
445 DWORD nTimeOut)
446 {
447 UNICODE_STRING PipeName;
448 BOOL Result;
449
450 RtlCreateUnicodeStringFromAsciiz(&PipeName,
451 (LPSTR)lpNamedPipeName);
452
453 Result = CallNamedPipeW(PipeName.Buffer,
454 lpInBuffer,
455 nInBufferSize,
456 lpOutBuffer,
457 nOutBufferSize,
458 lpBytesRead,
459 nTimeOut);
460
461 RtlFreeUnicodeString(&PipeName);
462
463 return(Result);
464 }
465
466
467 /*
468 * @implemented
469 */
470 BOOL STDCALL
471 CallNamedPipeW(LPCWSTR lpNamedPipeName,
472 LPVOID lpInBuffer,
473 DWORD nInBufferSize,
474 LPVOID lpOutBuffer,
475 DWORD nOutBufferSize,
476 LPDWORD lpBytesRead,
477 DWORD nTimeOut)
478 {
479 HANDLE hPipe = INVALID_HANDLE_VALUE;
480 BOOL bRetry = TRUE;
481 BOOL bError = FALSE;
482 DWORD dwPipeMode;
483
484 while (TRUE)
485 {
486 hPipe = CreateFileW(lpNamedPipeName,
487 GENERIC_READ | GENERIC_WRITE,
488 FILE_SHARE_READ | FILE_SHARE_WRITE,
489 NULL,
490 OPEN_EXISTING,
491 FILE_ATTRIBUTE_NORMAL,
492 NULL);
493 if (hPipe != INVALID_HANDLE_VALUE)
494 break;
495
496 if (bRetry == FALSE)
497 return(FALSE);
498
499 WaitNamedPipeW(lpNamedPipeName,
500 nTimeOut);
501
502 bRetry = FALSE;
503 }
504
505 dwPipeMode = PIPE_READMODE_MESSAGE;
506 bError = SetNamedPipeHandleState(hPipe,
507 &dwPipeMode,
508 NULL,
509 NULL);
510 if (!bError)
511 {
512 CloseHandle(hPipe);
513 return(FALSE);
514 }
515
516 bError = TransactNamedPipe(hPipe,
517 lpInBuffer,
518 nInBufferSize,
519 lpOutBuffer,
520 nOutBufferSize,
521 lpBytesRead,
522 NULL);
523 CloseHandle(hPipe);
524
525 return(bError);
526 }
527
528
529 /*
530 * @implemented
531 */
532 BOOL STDCALL
533 DisconnectNamedPipe(HANDLE hNamedPipe)
534 {
535 IO_STATUS_BLOCK Iosb;
536 NTSTATUS Status;
537
538 Status = NtFsControlFile(hNamedPipe,
539 NULL,
540 NULL,
541 NULL,
542 &Iosb,
543 FSCTL_PIPE_DISCONNECT,
544 NULL,
545 0,
546 NULL,
547 0);
548 if (Status == STATUS_PENDING)
549 {
550 Status = NtWaitForSingleObject(hNamedPipe,
551 FALSE,
552 NULL);
553 if (!NT_SUCCESS(Status))
554 {
555 SetLastErrorByStatus(Status);
556 return(FALSE);
557 }
558 }
559
560 if (!NT_SUCCESS(Status))
561 {
562 SetLastErrorByStatus(Status);
563 return(FALSE);
564 }
565 return(TRUE);
566 }
567
568
569 /*
570 * @unimplemented
571 */
572 BOOL STDCALL
573 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
574 LPDWORD lpState,
575 LPDWORD lpCurInstances,
576 LPDWORD lpMaxCollectionCount,
577 LPDWORD lpCollectDataTimeout,
578 LPWSTR lpUserName,
579 DWORD nMaxUserNameSize)
580 {
581 IO_STATUS_BLOCK StatusBlock;
582 NTSTATUS Status;
583
584 if (lpState != NULL)
585 {
586 FILE_PIPE_INFORMATION PipeInfo;
587
588 Status = NtQueryInformationFile(hNamedPipe,
589 &StatusBlock,
590 &PipeInfo,
591 sizeof(FILE_PIPE_INFORMATION),
592 FilePipeInformation);
593 if (!NT_SUCCESS(Status))
594 {
595 SetLastErrorByStatus(Status);
596 return FALSE;
597 }
598
599 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
600 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
601 }
602
603 if(lpCurInstances != NULL)
604 {
605 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
606
607 Status = NtQueryInformationFile(hNamedPipe,
608 &StatusBlock,
609 &LocalInfo,
610 sizeof(FILE_PIPE_LOCAL_INFORMATION),
611 FilePipeLocalInformation);
612 if(!NT_SUCCESS(Status))
613 {
614 SetLastErrorByStatus(Status);
615 return FALSE;
616 }
617
618 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
619 }
620
621 if(lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
622 {
623 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
624
625 Status = NtQueryInformationFile(hNamedPipe,
626 &StatusBlock,
627 &RemoteInfo,
628 sizeof(FILE_PIPE_REMOTE_INFORMATION),
629 FilePipeRemoteInformation);
630 if(!NT_SUCCESS(Status))
631 {
632 SetLastErrorByStatus(Status);
633 return FALSE;
634 }
635
636 if(lpMaxCollectionCount != NULL)
637 {
638 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
639 }
640
641 if(lpCollectDataTimeout != NULL)
642 {
643 /* FIXME */
644 *lpCollectDataTimeout = 0;
645 }
646 }
647
648 if(lpUserName != NULL)
649 {
650 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
651 retreive the user name with GetUserName(), revert the impersonation
652 and finally restore the thread token */
653 }
654
655 return TRUE;
656 }
657
658
659 /*
660 * @implemented
661 */
662 BOOL STDCALL
663 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
664 LPDWORD lpState,
665 LPDWORD lpCurInstances,
666 LPDWORD lpMaxCollectionCount,
667 LPDWORD lpCollectDataTimeout,
668 LPSTR lpUserName,
669 DWORD nMaxUserNameSize)
670 {
671 UNICODE_STRING UserNameW;
672 ANSI_STRING UserNameA;
673 BOOL Ret;
674
675 if(lpUserName != NULL)
676 {
677 UserNameW.Length = 0;
678 UserNameW.MaximumLength = nMaxUserNameSize * sizeof(WCHAR);
679 UserNameW.Buffer = HeapAlloc(GetCurrentProcess(), 0, UserNameW.MaximumLength);
680
681 UserNameA.Buffer = lpUserName;
682 UserNameA.Length = 0;
683 UserNameA.MaximumLength = nMaxUserNameSize;
684 }
685
686 Ret = GetNamedPipeHandleStateW(hNamedPipe,
687 lpState,
688 lpCurInstances,
689 lpMaxCollectionCount,
690 lpCollectDataTimeout,
691 UserNameW.Buffer,
692 nMaxUserNameSize);
693
694 if(Ret && lpUserName != NULL)
695 {
696 NTSTATUS Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
697 if(!NT_SUCCESS(Status))
698 {
699 SetLastErrorByStatus(Status);
700 Ret = FALSE;
701 }
702 }
703
704 if(UserNameW.Buffer != NULL)
705 {
706 HeapFree(GetCurrentProcess(), 0, UserNameW.Buffer);
707 }
708
709 return Ret;
710 }
711
712
713 /*
714 * @implemented
715 */
716 BOOL STDCALL
717 GetNamedPipeInfo(HANDLE hNamedPipe,
718 LPDWORD lpFlags,
719 LPDWORD lpOutBufferSize,
720 LPDWORD lpInBufferSize,
721 LPDWORD lpMaxInstances)
722 {
723 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
724 IO_STATUS_BLOCK StatusBlock;
725 NTSTATUS Status;
726
727 Status = NtQueryInformationFile(hNamedPipe,
728 &StatusBlock,
729 &PipeLocalInformation,
730 sizeof(FILE_PIPE_LOCAL_INFORMATION),
731 FilePipeLocalInformation);
732 if (!NT_SUCCESS(Status))
733 {
734 SetLastErrorByStatus(Status);
735 return(FALSE);
736 }
737
738 if (lpFlags != NULL)
739 {
740 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
741 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
742 }
743
744 if (lpOutBufferSize != NULL)
745 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
746
747 if (lpInBufferSize != NULL)
748 *lpInBufferSize = PipeLocalInformation.InboundQuota;
749
750 if (lpMaxInstances != NULL)
751 {
752 if (PipeLocalInformation.MaximumInstances >= 255)
753 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
754 else
755 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
756 }
757
758 return(TRUE);
759 }
760
761
762 /*
763 * @implemented
764 */
765 BOOL STDCALL
766 PeekNamedPipe(HANDLE hNamedPipe,
767 LPVOID lpBuffer,
768 DWORD nBufferSize,
769 LPDWORD lpBytesRead,
770 LPDWORD lpTotalBytesAvail,
771 LPDWORD lpBytesLeftThisMessage)
772 {
773 PFILE_PIPE_PEEK_BUFFER Buffer;
774 IO_STATUS_BLOCK Iosb;
775 ULONG BufferSize;
776 NTSTATUS Status;
777
778 BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
779 Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
780 0,
781 BufferSize);
782
783 Status = NtFsControlFile(hNamedPipe,
784 NULL,
785 NULL,
786 NULL,
787 &Iosb,
788 FSCTL_PIPE_PEEK,
789 NULL,
790 0,
791 Buffer,
792 BufferSize);
793 if (Status == STATUS_PENDING)
794 {
795 Status = NtWaitForSingleObject(hNamedPipe,
796 FALSE,
797 NULL);
798 if (NT_SUCCESS(Status))
799 Status = Iosb.Status;
800 }
801
802 if (Status == STATUS_BUFFER_OVERFLOW)
803 {
804 Status = STATUS_SUCCESS;
805 }
806
807 if (!NT_SUCCESS(Status))
808 {
809 RtlFreeHeap(RtlGetProcessHeap(),
810 0,
811 Buffer);
812 SetLastErrorByStatus(Status);
813 return(FALSE);
814 }
815
816 if (lpTotalBytesAvail != NULL)
817 {
818 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
819 }
820
821 if (lpBytesRead != NULL)
822 {
823 *lpBytesRead = Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER);
824 }
825
826 if (lpBytesLeftThisMessage != NULL)
827 {
828 *lpBytesLeftThisMessage = Buffer->MessageLength -
829 (Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER));
830 }
831
832 if (lpBuffer != NULL)
833 {
834 memcpy(lpBuffer, Buffer->Data,
835 min(nBufferSize, Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER)));
836 }
837
838 RtlFreeHeap(RtlGetProcessHeap(),
839 0,
840 Buffer);
841
842 return(TRUE);
843 }
844
845
846 /*
847 * @implemented
848 */
849 BOOL STDCALL
850 TransactNamedPipe(IN HANDLE hNamedPipe,
851 IN LPVOID lpInBuffer,
852 IN DWORD nInBufferSize,
853 OUT LPVOID lpOutBuffer,
854 IN DWORD nOutBufferSize,
855 OUT LPDWORD lpBytesRead OPTIONAL,
856 IN LPOVERLAPPED lpOverlapped OPTIONAL)
857 {
858 NTSTATUS Status;
859
860 if (lpBytesRead != NULL)
861 {
862 *lpBytesRead = 0;
863 }
864
865 if (lpOverlapped != NULL)
866 {
867 PVOID ApcContext;
868
869 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
870 lpOverlapped->Internal = STATUS_PENDING;
871
872 Status = NtFsControlFile(hNamedPipe,
873 lpOverlapped->hEvent,
874 NULL,
875 ApcContext,
876 (PIO_STATUS_BLOCK)lpOverlapped,
877 FSCTL_PIPE_TRANSCEIVE,
878 lpInBuffer,
879 nInBufferSize,
880 lpOutBuffer,
881 nOutBufferSize);
882
883 /* return FALSE in case of failure and pending operations! */
884 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
885 {
886 SetLastErrorByStatus(Status);
887 return FALSE;
888 }
889
890 if (lpBytesRead != NULL)
891 {
892 *lpBytesRead = lpOverlapped->InternalHigh;
893 }
894 }
895 else
896 {
897 IO_STATUS_BLOCK Iosb;
898
899 Status = NtFsControlFile(hNamedPipe,
900 NULL,
901 NULL,
902 NULL,
903 &Iosb,
904 FSCTL_PIPE_TRANSCEIVE,
905 lpInBuffer,
906 nInBufferSize,
907 lpOutBuffer,
908 nOutBufferSize);
909
910 /* wait in case operation is pending */
911 if (Status == STATUS_PENDING)
912 {
913 Status = NtWaitForSingleObject(hNamedPipe,
914 FALSE,
915 NULL);
916 if (NT_SUCCESS(Status))
917 {
918 Status = Iosb.Status;
919 }
920 }
921
922 if (NT_SUCCESS(Status))
923 {
924 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
925 check that case either and crashes (only after the operation
926 completed) */
927 *lpBytesRead = Iosb.Information;
928 }
929 else
930 {
931 SetLastErrorByStatus(Status);
932 return FALSE;
933 }
934 }
935
936 return TRUE;
937 }
938
939 /* EOF */