[NPFS]
[reactos.git] / reactos / dll / win32 / 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 #define NDEBUG
14 #include <debug.h>
15 DEBUG_CHANNEL(kernel32file);
16
17 #define USING_PROPER_NPFS_WAIT_SEMANTICS
18
19 /* FUNCTIONS ****************************************************************/
20
21 /*
22 * @implemented
23 */
24 HANDLE
25 WINAPI
26 CreateNamedPipeA(LPCSTR lpName,
27 DWORD dwOpenMode,
28 DWORD dwPipeMode,
29 DWORD nMaxInstances,
30 DWORD nOutBufferSize,
31 DWORD nInBufferSize,
32 DWORD nDefaultTimeOut,
33 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
34 {
35 PUNICODE_STRING NameU = &NtCurrentTeb()->StaticUnicodeString;
36 ANSI_STRING NameA;
37
38 /* Initialize the string as ANSI_STRING and convert to Unicode */
39 RtlInitAnsiString(&NameA, (LPSTR)lpName);
40 RtlAnsiStringToUnicodeString(NameU, &NameA, FALSE);
41
42 /* Call the Unicode API */
43 return CreateNamedPipeW(NameU->Buffer,
44 dwOpenMode,
45 dwPipeMode,
46 nMaxInstances,
47 nOutBufferSize,
48 nInBufferSize,
49 nDefaultTimeOut,
50 lpSecurityAttributes);
51 }
52
53
54 /*
55 * @implemented
56 */
57 HANDLE
58 WINAPI
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 = 0;
75 ULONG WriteModeMessage;
76 ULONG ReadModeMessage;
77 ULONG NonBlocking;
78 IO_STATUS_BLOCK Iosb;
79 ULONG ShareAccess = 0, Attributes;
80 LARGE_INTEGER DefaultTimeOut;
81 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
82
83 /* Check for valid instances */
84 if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES)
85 {
86 /* Fail */
87 SetLastError(ERROR_INVALID_PARAMETER);
88 return INVALID_HANDLE_VALUE;
89 }
90
91 /* Convert to NT syntax */
92 if (nMaxInstances == PIPE_UNLIMITED_INSTANCES)
93 nMaxInstances = -1;
94
95 /* Convert the name */
96 Result = RtlDosPathNameToNtPathName_U(lpName,
97 &NamedPipeName,
98 NULL,
99 NULL);
100 if (!Result)
101 {
102 /* Conversion failed */
103 SetLastError(ERROR_PATH_NOT_FOUND);
104 return INVALID_HANDLE_VALUE;
105 }
106
107 TRACE("Pipe name: %wZ\n", &NamedPipeName);
108 TRACE("Pipe name: %S\n", NamedPipeName.Buffer);
109
110 /* Always case insensitive, check if we got extra attributes */
111 Attributes = OBJ_CASE_INSENSITIVE;
112 if(lpSecurityAttributes)
113 {
114 /* We did; get the security descriptor */
115 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
116
117 /* And check if this is pipe's handle will beinheritable */
118 if (lpSecurityAttributes->bInheritHandle)
119 Attributes |= OBJ_INHERIT;
120 }
121
122 /* Now we can initialize the object attributes */
123 InitializeObjectAttributes(&ObjectAttributes,
124 &NamedPipeName,
125 Attributes,
126 NULL,
127 SecurityDescriptor);
128
129 /* Setup the default Desired Access */
130 DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC |
131 WRITE_OWNER |
132 ACCESS_SYSTEM_SECURITY));
133
134 /* Convert to NT Create Flags */
135 if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
136 {
137 CreateOptions |= FILE_WRITE_THROUGH;
138 }
139
140 if (!(dwOpenMode & FILE_FLAG_OVERLAPPED))
141 {
142 CreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
143 }
144
145 /* Handle all open modes */
146 if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
147 {
148 ShareAccess |= FILE_SHARE_READ;
149 DesiredAccess |= GENERIC_WRITE;
150 }
151
152 if (dwOpenMode & PIPE_ACCESS_INBOUND)
153 {
154 ShareAccess |= FILE_SHARE_WRITE;
155 DesiredAccess |= GENERIC_READ;
156 }
157
158 /* Handle the type flags */
159 if (dwPipeMode & PIPE_TYPE_MESSAGE)
160 {
161 WriteModeMessage = FILE_PIPE_MESSAGE_TYPE;
162 }
163 else
164 {
165 WriteModeMessage = FILE_PIPE_BYTE_STREAM_TYPE;
166 }
167
168 /* Handle the mode flags */
169 if (dwPipeMode & PIPE_READMODE_MESSAGE)
170 {
171 ReadModeMessage = FILE_PIPE_MESSAGE_MODE;
172 }
173 else
174 {
175 ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE;
176 }
177
178 /* Handle the blocking mode */
179 if (dwPipeMode & PIPE_NOWAIT)
180 {
181 NonBlocking = FILE_PIPE_COMPLETE_OPERATION;
182 }
183 else
184 {
185 NonBlocking = FILE_PIPE_QUEUE_OPERATION;
186 }
187
188 /* Check if we have a timeout */
189 if (nDefaultTimeOut)
190 {
191 /* Convert the time to NT format */
192 DefaultTimeOut.QuadPart = UInt32x32To64(nDefaultTimeOut, -10000);
193 }
194 else
195 {
196 /* Use default timeout of 50 ms */
197 DefaultTimeOut.QuadPart = -500000;
198 }
199
200 /* Now create the pipe */
201 Status = NtCreateNamedPipeFile(&PipeHandle,
202 DesiredAccess,
203 &ObjectAttributes,
204 &Iosb,
205 ShareAccess,
206 FILE_OPEN_IF,
207 CreateOptions,
208 WriteModeMessage,
209 ReadModeMessage,
210 NonBlocking,
211 nMaxInstances,
212 nInBufferSize,
213 nOutBufferSize,
214 &DefaultTimeOut);
215
216 /* Normalize special error codes */
217 if ((Status == STATUS_INVALID_DEVICE_REQUEST) ||
218 (Status == STATUS_NOT_SUPPORTED))
219 {
220 Status = STATUS_OBJECT_NAME_INVALID;
221 }
222
223 /* Free the name */
224 RtlFreeHeap(RtlGetProcessHeap(),
225 0,
226 NamedPipeName.Buffer);
227
228 /* Check status */
229 if (!NT_SUCCESS(Status))
230 {
231 /* Failed to create it */
232 WARN("NtCreateNamedPipe failed (Status %x)!\n", Status);
233 SetLastErrorByStatus (Status);
234 return INVALID_HANDLE_VALUE;
235 }
236
237 /* Return the handle */
238 return PipeHandle;
239 }
240
241
242 /*
243 * @implemented
244 */
245 BOOL
246 WINAPI
247 WaitNamedPipeA(LPCSTR lpNamedPipeName,
248 DWORD nTimeOut)
249 {
250 BOOL r;
251 UNICODE_STRING NameU;
252
253 /* Convert the name to Unicode */
254 Basep8BitStringToHeapUnicodeString(&NameU, lpNamedPipeName);
255
256 /* Call the Unicode API */
257 r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
258
259 /* Free the Unicode string */
260 RtlFreeUnicodeString(&NameU);
261
262 /* Return result */
263 return r;
264 }
265
266
267 /*
268 * @implemented
269 */
270 BOOL
271 WINAPI
272 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
273 DWORD nTimeOut)
274 {
275 UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix;
276 ULONG NameLength;
277 ULONG i;
278 PWCHAR p;
279 ULONG Type;
280 OBJECT_ATTRIBUTES ObjectAttributes;
281 NTSTATUS Status;
282 HANDLE FileHandle;
283 IO_STATUS_BLOCK IoStatusBlock;
284 ULONG WaitPipeInfoSize;
285 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;
286
287 /* Start by making a unicode string of the name */
288 TRACE("Sent path: %S\n", lpNamedPipeName);
289 RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName);
290 NameLength = NamedPipeName.Length / sizeof(WCHAR);
291
292 /* All slashes must become backslashes */
293 for (i = 0; i < NameLength; i++)
294 {
295 /* Check and convert */
296 if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
297 }
298
299 /* Find the path type of the name we were given */
300 NewName = NamedPipeName;
301 Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);
302
303 /* Check if this was a device path, ie : "\\.\pipe\name" */
304 if (Type == RtlPathTypeLocalDevice)
305 {
306 /* Make sure it's a valid prefix */
307 RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
308 RtlPrefixString((PANSI_STRING)&PipePrefix, (PANSI_STRING)&NewName, TRUE);
309
310 /* Move past it */
311 NewName.Buffer += 9;
312 NewName.Length -= 9 * sizeof(WCHAR);
313
314 /* Initialize the Dos Devices name */
315 TRACE("NewName: %wZ\n", &NewName);
316 RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
317 }
318 else if (Type == RtlPathTypeRootLocalDevice)
319 {
320 /* The path is \\server\\pipe\name; find the pipename itself */
321 p = &NewName.Buffer[2];
322
323 /* First loop to get past the server name */
324 do
325 {
326 /* Check if this is a backslash */
327 if (*p == L'\\') break;
328
329 /* Check next */
330 p++;
331 } while (*p);
332
333 /* Now make sure the full name contains "pipe\" */
334 if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\"))))
335 {
336 /* Get to the pipe name itself now */
337 p += sizeof("pipe\\") - 1;
338 }
339 else
340 {
341 /* The name is invalid */
342 WARN("Invalid name!\n");
343 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD);
344 return FALSE;
345 }
346
347 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
348 }
349 else
350 {
351 WARN("Invalid path type\n");
352 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD);
353 return FALSE;
354 }
355
356 /* Now calculate the total length of the structure and allocate it */
357 WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
358 NewName.Length;
359 WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
360 if (WaitPipeInfo == NULL)
361 {
362 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
363 return FALSE;
364 }
365
366 /* Initialize the object attributes */
367 TRACE("Opening: %wZ\n", &DevicePath);
368 InitializeObjectAttributes(&ObjectAttributes,
369 &DevicePath,
370 OBJ_CASE_INSENSITIVE,
371 NULL,
372 NULL);
373
374 /* Open the path */
375 Status = NtOpenFile(&FileHandle,
376 FILE_READ_ATTRIBUTES | SYNCHRONIZE,
377 &ObjectAttributes,
378 &IoStatusBlock,
379 FILE_SHARE_READ | FILE_SHARE_WRITE,
380 FILE_SYNCHRONOUS_IO_NONALERT);
381 if (!NT_SUCCESS(Status))
382 {
383 /* Fail; couldn't open */
384 WARN("Status: %lx\n", Status);
385 SetLastErrorByStatus(Status);
386 RtlFreeUnicodeString(&NamedPipeName);
387 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
388 return FALSE;
389 }
390
391 /* Check what timeout we got */
392 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
393 {
394 /* Don't use a timeout */
395 WaitPipeInfo->TimeoutSpecified = FALSE;
396 }
397 else
398 {
399 /* Check if we should wait forever */
400 if (nTimeOut == NMPWAIT_WAIT_FOREVER)
401 {
402 /* Set the max */
403 WaitPipeInfo->Timeout.LowPart = 0;
404 WaitPipeInfo->Timeout.HighPart = 0x80000000;
405 }
406 else
407 {
408 /* Convert to NT format */
409 WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut);
410 }
411
412 /* In both cases, we do have a timeout */
413 WaitPipeInfo->TimeoutSpecified = TRUE;
414 }
415
416 /* Set the length and copy the name */
417 WaitPipeInfo->NameLength = NewName.Length;
418 RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);
419
420 /* Get rid of the full name */
421 RtlFreeUnicodeString(&NamedPipeName);
422
423 /* Let NPFS know of our request */
424 Status = NtFsControlFile(FileHandle,
425 NULL,
426 NULL,
427 NULL,
428 &IoStatusBlock,
429 FSCTL_PIPE_WAIT,
430 WaitPipeInfo,
431 WaitPipeInfoSize,
432 NULL,
433 0);
434
435 /* Free our pipe info data and close the handle */
436 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
437 NtClose(FileHandle);
438
439 /* Check the status */
440 if (!NT_SUCCESS(Status))
441 {
442 /* Failure to wait on the pipe */
443 WARN("Status: %lx\n", Status);
444 SetLastErrorByStatus (Status);
445 return FALSE;
446 }
447
448 /* Success */
449 return TRUE;
450 }
451
452
453 /*
454 * @implemented
455 */
456 BOOL
457 WINAPI
458 ConnectNamedPipe(IN HANDLE hNamedPipe,
459 IN LPOVERLAPPED lpOverlapped)
460 {
461 NTSTATUS Status;
462
463 if (lpOverlapped != NULL)
464 {
465 PVOID ApcContext;
466
467 lpOverlapped->Internal = STATUS_PENDING;
468 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
469
470 Status = NtFsControlFile(hNamedPipe,
471 lpOverlapped->hEvent,
472 NULL,
473 ApcContext,
474 (PIO_STATUS_BLOCK)lpOverlapped,
475 FSCTL_PIPE_LISTEN,
476 NULL,
477 0,
478 NULL,
479 0);
480
481 /* return FALSE in case of failure and pending operations! */
482 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
483 {
484 SetLastErrorByStatus(Status);
485 return FALSE;
486 }
487 }
488 else
489 {
490 IO_STATUS_BLOCK Iosb;
491
492 Status = NtFsControlFile(hNamedPipe,
493 NULL,
494 NULL,
495 NULL,
496 &Iosb,
497 FSCTL_PIPE_LISTEN,
498 NULL,
499 0,
500 NULL,
501 0);
502
503 /* wait in case operation is pending */
504 if (Status == STATUS_PENDING)
505 {
506 Status = NtWaitForSingleObject(hNamedPipe,
507 FALSE,
508 NULL);
509 if (NT_SUCCESS(Status))
510 {
511 Status = Iosb.Status;
512 }
513 }
514
515 if (!NT_SUCCESS(Status))
516 {
517 SetLastErrorByStatus(Status);
518 return FALSE;
519 }
520 }
521
522 return TRUE;
523 }
524
525
526 /*
527 * @implemented
528 */
529 BOOL
530 WINAPI
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 if (!NT_SUCCESS(Status))
579 {
580 SetLastErrorByStatus(Status);
581 return FALSE;
582 }
583 }
584
585 /* Now set the new settings */
586 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ?
587 *lpMaxCollectionCount :
588 RemoteSettings.MaximumCollectionCount;
589 if (lpCollectDataTimeout)
590 {
591 /* Convert it to Quad */
592 RemoteSettings.CollectDataTime.QuadPart =
593 -(LONGLONG)UInt32x32To64(10000, *lpCollectDataTimeout);
594 }
595
596 /* Tell the driver to change them */
597 Status = NtSetInformationFile(hNamedPipe,
598 &Iosb,
599 &RemoteSettings,
600 sizeof(FILE_PIPE_REMOTE_INFORMATION),
601 FilePipeRemoteInformation);
602 if (!NT_SUCCESS(Status))
603 {
604 SetLastErrorByStatus(Status);
605 return FALSE;
606 }
607 }
608
609 return TRUE;
610 }
611
612
613 /*
614 * @implemented
615 */
616 BOOL
617 WINAPI
618 CallNamedPipeA(LPCSTR lpNamedPipeName,
619 LPVOID lpInBuffer,
620 DWORD nInBufferSize,
621 LPVOID lpOutBuffer,
622 DWORD nOutBufferSize,
623 LPDWORD lpBytesRead,
624 DWORD nTimeOut)
625 {
626 PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString;
627 ANSI_STRING AnsiPipe;
628
629 /* Initialize the string as ANSI_STRING and convert to Unicode */
630 RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName);
631 RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE);
632
633 /* Call the Unicode function */
634 return CallNamedPipeW(PipeName->Buffer,
635 lpInBuffer,
636 nInBufferSize,
637 lpOutBuffer,
638 nOutBufferSize,
639 lpBytesRead,
640 nTimeOut);
641 }
642
643
644 /*
645 * @implemented
646 */
647 BOOL
648 WINAPI
649 CallNamedPipeW(LPCWSTR lpNamedPipeName,
650 LPVOID lpInBuffer,
651 DWORD nInBufferSize,
652 LPVOID lpOutBuffer,
653 DWORD nOutBufferSize,
654 LPDWORD lpBytesRead,
655 DWORD nTimeOut)
656 {
657 HANDLE hPipe;
658 BOOL bRetry = TRUE;
659 BOOL bError;
660 DWORD dwPipeMode;
661
662 while (TRUE)
663 {
664 /* Try creating it */
665 hPipe = CreateFileW(lpNamedPipeName,
666 GENERIC_READ | GENERIC_WRITE,
667 FILE_SHARE_READ | FILE_SHARE_WRITE,
668 NULL,
669 OPEN_EXISTING,
670 FILE_ATTRIBUTE_NORMAL,
671 NULL);
672
673 /* Success, break out */
674 if (hPipe != INVALID_HANDLE_VALUE)
675 break;
676
677 /* Already tried twice, give up */
678 if (bRetry == FALSE)
679 return FALSE;
680
681 /* Wait on it */
682 WaitNamedPipeW(lpNamedPipeName, nTimeOut);
683
684 /* Get ready to try again */
685 bRetry = FALSE;
686 }
687
688 /* Set the pipe mode */
689 dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
690 bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL);
691 if (!bError)
692 {
693 /* Couldn't change state, fail */
694 CloseHandle(hPipe);
695 return FALSE;
696 }
697
698 /* Do the transact */
699 bError = TransactNamedPipe(hPipe,
700 lpInBuffer,
701 nInBufferSize,
702 lpOutBuffer,
703 nOutBufferSize,
704 lpBytesRead,
705 NULL);
706
707 /* Close the handle */
708 CloseHandle(hPipe);
709
710 return bError;
711 }
712
713
714 /*
715 * @implemented
716 */
717 BOOL
718 WINAPI
719 DisconnectNamedPipe(HANDLE hNamedPipe)
720 {
721 IO_STATUS_BLOCK Iosb;
722 NTSTATUS Status;
723
724 /* Send the FSCTL to the driver */
725 Status = NtFsControlFile(hNamedPipe,
726 NULL,
727 NULL,
728 NULL,
729 &Iosb,
730 FSCTL_PIPE_DISCONNECT,
731 NULL,
732 0,
733 NULL,
734 0);
735 if (Status == STATUS_PENDING)
736 {
737 /* Wait on NPFS to finish and get updated status */
738 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
739 if (NT_SUCCESS(Status))
740 Status = Iosb.Status;
741 }
742
743 /* Check for error */
744 if (!NT_SUCCESS(Status))
745 {
746 /* Fail */
747 SetLastErrorByStatus(Status);
748 return FALSE;
749 }
750
751 return TRUE;
752 }
753
754
755 /*
756 * @unimplemented
757 */
758 BOOL
759 WINAPI
760 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
761 LPDWORD lpState,
762 LPDWORD lpCurInstances,
763 LPDWORD lpMaxCollectionCount,
764 LPDWORD lpCollectDataTimeout,
765 LPWSTR lpUserName,
766 DWORD nMaxUserNameSize)
767 {
768 IO_STATUS_BLOCK StatusBlock;
769 NTSTATUS Status;
770
771 if (lpState != NULL)
772 {
773 FILE_PIPE_INFORMATION PipeInfo;
774
775 Status = NtQueryInformationFile(hNamedPipe,
776 &StatusBlock,
777 &PipeInfo,
778 sizeof(FILE_PIPE_INFORMATION),
779 FilePipeInformation);
780 if (!NT_SUCCESS(Status))
781 {
782 SetLastErrorByStatus(Status);
783 return FALSE;
784 }
785
786 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT);
787 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
788 }
789
790 if(lpCurInstances != NULL)
791 {
792 FILE_PIPE_LOCAL_INFORMATION LocalInfo;
793
794 Status = NtQueryInformationFile(hNamedPipe,
795 &StatusBlock,
796 &LocalInfo,
797 sizeof(FILE_PIPE_LOCAL_INFORMATION),
798 FilePipeLocalInformation);
799 if (!NT_SUCCESS(Status))
800 {
801 SetLastErrorByStatus(Status);
802 return FALSE;
803 }
804
805 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES);
806 }
807
808 if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL)
809 {
810 FILE_PIPE_REMOTE_INFORMATION RemoteInfo;
811
812 Status = NtQueryInformationFile(hNamedPipe,
813 &StatusBlock,
814 &RemoteInfo,
815 sizeof(FILE_PIPE_REMOTE_INFORMATION),
816 FilePipeRemoteInformation);
817 if (!NT_SUCCESS(Status))
818 {
819 SetLastErrorByStatus(Status);
820 return FALSE;
821 }
822
823 if (lpMaxCollectionCount != NULL)
824 {
825 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount;
826 }
827
828 if(lpCollectDataTimeout != NULL)
829 {
830 /* FIXME */
831 *lpCollectDataTimeout = 0;
832 }
833 }
834
835 if (lpUserName != NULL)
836 {
837 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
838 retreive the user name with GetUserName(), revert the impersonation
839 and finally restore the thread token */
840 }
841
842 return TRUE;
843 }
844
845
846 /*
847 * @implemented
848 */
849 BOOL
850 WINAPI
851 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
852 LPDWORD lpState,
853 LPDWORD lpCurInstances,
854 LPDWORD lpMaxCollectionCount,
855 LPDWORD lpCollectDataTimeout,
856 LPSTR lpUserName,
857 DWORD nMaxUserNameSize)
858 {
859 UNICODE_STRING UserNameW = { 0, 0, NULL };
860 ANSI_STRING UserNameA;
861 BOOL Ret;
862
863 if(lpUserName != NULL)
864 {
865 UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR);
866 UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength);
867 if (UserNameW.Buffer == NULL)
868 {
869 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
870 return FALSE;
871 }
872
873 UserNameA.Buffer = lpUserName;
874 UserNameA.Length = 0;
875 UserNameA.MaximumLength = (USHORT)nMaxUserNameSize;
876 }
877
878 Ret = GetNamedPipeHandleStateW(hNamedPipe,
879 lpState,
880 lpCurInstances,
881 lpMaxCollectionCount,
882 lpCollectDataTimeout,
883 UserNameW.Buffer,
884 nMaxUserNameSize);
885 if (Ret && lpUserName != NULL)
886 {
887 NTSTATUS Status;
888
889 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer);
890 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE);
891 if (!NT_SUCCESS(Status))
892 {
893 SetLastErrorByStatus(Status);
894 Ret = FALSE;
895 }
896 }
897
898 if (UserNameW.Buffer != NULL)
899 {
900 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer);
901 }
902
903 return Ret;
904 }
905
906
907 /*
908 * @implemented
909 */
910 BOOL
911 WINAPI
912 GetNamedPipeInfo(HANDLE hNamedPipe,
913 LPDWORD lpFlags,
914 LPDWORD lpOutBufferSize,
915 LPDWORD lpInBufferSize,
916 LPDWORD lpMaxInstances)
917 {
918 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
919 IO_STATUS_BLOCK StatusBlock;
920 NTSTATUS Status;
921
922 Status = NtQueryInformationFile(hNamedPipe,
923 &StatusBlock,
924 &PipeLocalInformation,
925 sizeof(FILE_PIPE_LOCAL_INFORMATION),
926 FilePipeLocalInformation);
927 if (!NT_SUCCESS(Status))
928 {
929 SetLastErrorByStatus(Status);
930 return FALSE;
931 }
932
933 if (lpFlags != NULL)
934 {
935 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
936 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
937 }
938
939 if (lpOutBufferSize != NULL)
940 *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
941
942 if (lpInBufferSize != NULL)
943 *lpInBufferSize = PipeLocalInformation.InboundQuota;
944
945 if (lpMaxInstances != NULL)
946 {
947 if (PipeLocalInformation.MaximumInstances >= 255)
948 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
949 else
950 *lpMaxInstances = PipeLocalInformation.MaximumInstances;
951 }
952
953 return TRUE;
954 }
955
956
957 /*
958 * @implemented
959 */
960 BOOL
961 WINAPI
962 PeekNamedPipe(HANDLE hNamedPipe,
963 LPVOID lpBuffer,
964 DWORD nBufferSize,
965 LPDWORD lpBytesRead,
966 LPDWORD lpTotalBytesAvail,
967 LPDWORD lpBytesLeftThisMessage)
968 {
969 PFILE_PIPE_PEEK_BUFFER Buffer;
970 IO_STATUS_BLOCK Iosb;
971 ULONG BufferSize;
972 ULONG BytesRead;
973 NTSTATUS Status;
974
975 /* Calculate the buffer space that we'll need and allocate it */
976 BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
977 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
978 if (Buffer == NULL)
979 {
980 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
981 return FALSE;
982 }
983
984 /* Tell the driver to seek */
985 Status = NtFsControlFile(hNamedPipe,
986 NULL,
987 NULL,
988 NULL,
989 &Iosb,
990 FSCTL_PIPE_PEEK,
991 NULL,
992 0,
993 Buffer,
994 BufferSize);
995 if (Status == STATUS_PENDING)
996 {
997 /* Wait for npfs to be done, and update the status */
998 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL);
999 if (NT_SUCCESS(Status))
1000 Status = Iosb.Status;
1001 }
1002
1003 /* Overflow is success for us */
1004 if (Status == STATUS_BUFFER_OVERFLOW)
1005 Status = STATUS_SUCCESS;
1006
1007 /* If we failed */
1008 if (!NT_SUCCESS(Status))
1009 {
1010 /* Free the buffer and return failure */
1011 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1012 SetLastErrorByStatus(Status);
1013 return FALSE;
1014 }
1015
1016 /* Check if caller requested bytes available */
1017 if (lpTotalBytesAvail)
1018 *lpTotalBytesAvail = Buffer->ReadDataAvailable;
1019
1020 /* Calculate the bytes returned, minus our structure overhead */
1021 BytesRead = (ULONG)(Iosb.Information -
1022 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]));
1023
1024 /* Check if caller requested bytes read */
1025 if (lpBytesRead)
1026 {
1027 /* Return the bytes read */
1028 *lpBytesRead = BytesRead;
1029 }
1030
1031 /* Check if caller requested bytes left */
1032 if (lpBytesLeftThisMessage)
1033 {
1034 /* Calculate total minus what we returned and our structure overhead */
1035 *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead;
1036 }
1037
1038 /* Check if the caller wanted to see the actual data */
1039 if (lpBuffer)
1040 {
1041 /* Give him what he wants */
1042 RtlCopyMemory(lpBuffer,
1043 Buffer->Data,
1044 BytesRead);
1045 }
1046
1047 /* Free the buffer */
1048 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1049
1050 return TRUE;
1051 }
1052
1053
1054 /*
1055 * @implemented
1056 */
1057 BOOL
1058 WINAPI
1059 TransactNamedPipe(IN HANDLE hNamedPipe,
1060 IN LPVOID lpInBuffer,
1061 IN DWORD nInBufferSize,
1062 OUT LPVOID lpOutBuffer,
1063 IN DWORD nOutBufferSize,
1064 OUT LPDWORD lpBytesRead OPTIONAL,
1065 IN LPOVERLAPPED lpOverlapped OPTIONAL)
1066 {
1067 NTSTATUS Status;
1068
1069 if (lpBytesRead != NULL)
1070 {
1071 *lpBytesRead = 0;
1072 }
1073
1074 if (lpOverlapped != NULL)
1075 {
1076 PVOID ApcContext;
1077
1078 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
1079 lpOverlapped->Internal = STATUS_PENDING;
1080
1081 Status = NtFsControlFile(hNamedPipe,
1082 lpOverlapped->hEvent,
1083 NULL,
1084 ApcContext,
1085 (PIO_STATUS_BLOCK)lpOverlapped,
1086 FSCTL_PIPE_TRANSCEIVE,
1087 lpInBuffer,
1088 nInBufferSize,
1089 lpOutBuffer,
1090 nOutBufferSize);
1091 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1092 {
1093 SetLastErrorByStatus(Status);
1094 return FALSE;
1095 }
1096
1097 if (lpBytesRead != NULL)
1098 {
1099 *lpBytesRead = lpOverlapped->InternalHigh;
1100 }
1101 }
1102 else
1103 {
1104 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1105 IO_STATUS_BLOCK Iosb;
1106
1107 Status = NtFsControlFile(hNamedPipe,
1108 NULL,
1109 NULL,
1110 NULL,
1111 &Iosb,
1112 FSCTL_PIPE_TRANSCEIVE,
1113 lpInBuffer,
1114 nInBufferSize,
1115 lpOutBuffer,
1116 nOutBufferSize);
1117 if (Status == STATUS_PENDING)
1118 {
1119 Status = NtWaitForSingleObject(hNamedPipe,
1120 FALSE,
1121 NULL);
1122 if (NT_SUCCESS(Status))
1123 Status = Iosb.Status;
1124 }
1125
1126 if (NT_SUCCESS(Status))
1127 {
1128 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1129 check that case either and crashes (only after the operation
1130 completed) */
1131 *lpBytesRead = Iosb.Information;
1132 }
1133 else
1134 {
1135 SetLastErrorByStatus(Status);
1136 return FALSE;
1137 }
1138 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1139 DWORD nActualBytes;
1140
1141 while (0 != nInBufferSize &&
1142 WriteFile(hNamedPipe, lpInBuffer, nInBufferSize, &nActualBytes,
1143 NULL))
1144 {
1145 lpInBuffer = (LPVOID)((char *) lpInBuffer + nActualBytes);
1146 nInBufferSize -= nActualBytes;
1147 }
1148
1149 if (0 != nInBufferSize)
1150 {
1151 /* Must have dropped out of the while 'cause WriteFile failed */
1152 return FALSE;
1153 }
1154
1155 if (!ReadFile(hNamedPipe, lpOutBuffer, nOutBufferSize, &nActualBytes,
1156 NULL))
1157 {
1158 return FALSE;
1159 }
1160
1161 if (NULL != lpBytesRead)
1162 {
1163 *lpBytesRead = nActualBytes;
1164 }
1165 #endif
1166 }
1167
1168 return TRUE;
1169 }
1170
1171 /* EOF */