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