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