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