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