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