Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygennpipe.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS Win32 Kernel Library 00004 * FILE: lib/kernel32/file/npipe.c 00005 * PURPOSE: Named Pipe Functions 00006 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 00007 * Ariadne ( ariadne@xs4all.nl) 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <k32.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 DEBUG_CHANNEL(kernel32file); 00016 00017 //#define USING_PROPER_NPFS_WAIT_SEMANTICS 00018 00019 /* GLOBALS ********************************************************************/ 00020 00021 LONG ProcessPipeId; 00022 00023 /* FUNCTIONS ******************************************************************/ 00024 00025 /* 00026 * @implemented 00027 */ 00028 BOOL 00029 WINAPI 00030 CreatePipe(PHANDLE hReadPipe, 00031 PHANDLE hWritePipe, 00032 LPSECURITY_ATTRIBUTES lpPipeAttributes, 00033 DWORD nSize) 00034 { 00035 WCHAR Buffer[64]; 00036 UNICODE_STRING PipeName; 00037 OBJECT_ATTRIBUTES ObjectAttributes; 00038 IO_STATUS_BLOCK StatusBlock; 00039 LARGE_INTEGER DefaultTimeout; 00040 NTSTATUS Status; 00041 HANDLE ReadPipeHandle; 00042 HANDLE WritePipeHandle; 00043 LONG PipeId; 00044 ULONG Attributes; 00045 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 00046 00047 /* Set the timeout to 120 seconds */ 00048 DefaultTimeout.QuadPart = -1200000000; 00049 00050 /* Use default buffer size if desired */ 00051 if (!nSize) nSize = 0x1000; 00052 00053 /* Increase the Pipe ID */ 00054 PipeId = InterlockedIncrement(&ProcessPipeId); 00055 00056 /* Create the pipe name */ 00057 swprintf(Buffer, 00058 L"\\Device\\NamedPipe\\Win32Pipes.%08x.%08x", 00059 NtCurrentTeb()->ClientId.UniqueProcess, 00060 PipeId); 00061 RtlInitUnicodeString(&PipeName, Buffer); 00062 00063 /* Always use case insensitive */ 00064 Attributes = OBJ_CASE_INSENSITIVE; 00065 00066 /* Check if we got attributes */ 00067 if (lpPipeAttributes) 00068 { 00069 /* Use the attributes' SD instead */ 00070 SecurityDescriptor = lpPipeAttributes->lpSecurityDescriptor; 00071 00072 /* Set OBJ_INHERIT if requested */ 00073 if (lpPipeAttributes->bInheritHandle) Attributes |= OBJ_INHERIT; 00074 } 00075 00076 /* Initialize the attributes */ 00077 InitializeObjectAttributes(&ObjectAttributes, 00078 &PipeName, 00079 Attributes, 00080 NULL, 00081 SecurityDescriptor); 00082 00083 /* Create the named pipe */ 00084 Status = NtCreateNamedPipeFile(&ReadPipeHandle, 00085 GENERIC_READ |FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 00086 &ObjectAttributes, 00087 &StatusBlock, 00088 FILE_SHARE_READ | FILE_SHARE_WRITE, 00089 FILE_CREATE, 00090 FILE_SYNCHRONOUS_IO_NONALERT, 00091 FILE_PIPE_BYTE_STREAM_TYPE, 00092 FILE_PIPE_BYTE_STREAM_MODE, 00093 FILE_PIPE_QUEUE_OPERATION, 00094 1, 00095 nSize, 00096 nSize, 00097 &DefaultTimeout); 00098 if (!NT_SUCCESS(Status)) 00099 { 00100 /* Convert error and fail */ 00101 WARN("Status: %lx\n", Status); 00102 BaseSetLastNTError(Status); 00103 return FALSE; 00104 } 00105 00106 /* Now try opening it for write access */ 00107 Status = NtOpenFile(&WritePipeHandle, 00108 FILE_GENERIC_WRITE | SYNCHRONIZE, 00109 &ObjectAttributes, 00110 &StatusBlock, 00111 FILE_SHARE_READ, 00112 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); 00113 if (!NT_SUCCESS(Status)) 00114 { 00115 /* Convert error and fail */ 00116 WARN("Status: %lx\n", Status); 00117 NtClose(ReadPipeHandle); 00118 BaseSetLastNTError(Status); 00119 return FALSE; 00120 } 00121 00122 /* Return both handles */ 00123 *hReadPipe = ReadPipeHandle; 00124 *hWritePipe = WritePipeHandle; 00125 return TRUE; 00126 } 00127 00128 /* 00129 * @implemented 00130 */ 00131 HANDLE 00132 WINAPI 00133 CreateNamedPipeA(LPCSTR lpName, 00134 DWORD dwOpenMode, 00135 DWORD dwPipeMode, 00136 DWORD nMaxInstances, 00137 DWORD nOutBufferSize, 00138 DWORD nInBufferSize, 00139 DWORD nDefaultTimeOut, 00140 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 00141 { 00142 /* Call the W(ide) function */ 00143 ConvertWin32AnsiChangeApiToUnicodeApi(CreateNamedPipe, 00144 lpName, 00145 dwOpenMode, 00146 dwPipeMode, 00147 nMaxInstances, 00148 nOutBufferSize, 00149 nInBufferSize, 00150 nDefaultTimeOut, 00151 lpSecurityAttributes); 00152 } 00153 00154 00155 /* 00156 * @implemented 00157 */ 00158 HANDLE 00159 WINAPI 00160 CreateNamedPipeW(LPCWSTR lpName, 00161 DWORD dwOpenMode, 00162 DWORD dwPipeMode, 00163 DWORD nMaxInstances, 00164 DWORD nOutBufferSize, 00165 DWORD nInBufferSize, 00166 DWORD nDefaultTimeOut, 00167 LPSECURITY_ATTRIBUTES lpSecurityAttributes) 00168 { 00169 UNICODE_STRING NamedPipeName; 00170 BOOL Result; 00171 NTSTATUS Status; 00172 OBJECT_ATTRIBUTES ObjectAttributes; 00173 HANDLE PipeHandle; 00174 ACCESS_MASK DesiredAccess; 00175 ULONG CreateOptions = 0; 00176 ULONG WriteModeMessage; 00177 ULONG ReadModeMessage; 00178 ULONG NonBlocking; 00179 IO_STATUS_BLOCK Iosb; 00180 ULONG ShareAccess = 0, Attributes; 00181 LARGE_INTEGER DefaultTimeOut; 00182 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 00183 00184 /* Check for valid instances */ 00185 if (nMaxInstances == 0 || nMaxInstances > PIPE_UNLIMITED_INSTANCES) 00186 { 00187 /* Fail */ 00188 SetLastError(ERROR_INVALID_PARAMETER); 00189 return INVALID_HANDLE_VALUE; 00190 } 00191 00192 /* Convert to NT syntax */ 00193 if (nMaxInstances == PIPE_UNLIMITED_INSTANCES) 00194 nMaxInstances = -1; 00195 00196 /* Convert the name */ 00197 Result = RtlDosPathNameToNtPathName_U(lpName, 00198 &NamedPipeName, 00199 NULL, 00200 NULL); 00201 if (!Result) 00202 { 00203 /* Conversion failed */ 00204 SetLastError(ERROR_PATH_NOT_FOUND); 00205 return INVALID_HANDLE_VALUE; 00206 } 00207 00208 TRACE("Pipe name: %wZ\n", &NamedPipeName); 00209 TRACE("Pipe name: %S\n", NamedPipeName.Buffer); 00210 00211 /* Always case insensitive, check if we got extra attributes */ 00212 Attributes = OBJ_CASE_INSENSITIVE; 00213 if(lpSecurityAttributes) 00214 { 00215 /* We did; get the security descriptor */ 00216 SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor; 00217 00218 /* And check if this is pipe's handle will beinheritable */ 00219 if (lpSecurityAttributes->bInheritHandle) 00220 Attributes |= OBJ_INHERIT; 00221 } 00222 00223 /* Now we can initialize the object attributes */ 00224 InitializeObjectAttributes(&ObjectAttributes, 00225 &NamedPipeName, 00226 Attributes, 00227 NULL, 00228 SecurityDescriptor); 00229 00230 /* Setup the default Desired Access */ 00231 DesiredAccess = SYNCHRONIZE | (dwOpenMode & (WRITE_DAC | 00232 WRITE_OWNER | 00233 ACCESS_SYSTEM_SECURITY)); 00234 00235 /* Convert to NT Create Flags */ 00236 if (dwOpenMode & FILE_FLAG_WRITE_THROUGH) 00237 { 00238 CreateOptions |= FILE_WRITE_THROUGH; 00239 } 00240 00241 if (!(dwOpenMode & FILE_FLAG_OVERLAPPED)) 00242 { 00243 CreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT; 00244 } 00245 00246 /* Handle all open modes */ 00247 if (dwOpenMode & PIPE_ACCESS_OUTBOUND) 00248 { 00249 ShareAccess |= FILE_SHARE_READ; 00250 DesiredAccess |= GENERIC_WRITE; 00251 } 00252 00253 if (dwOpenMode & PIPE_ACCESS_INBOUND) 00254 { 00255 ShareAccess |= FILE_SHARE_WRITE; 00256 DesiredAccess |= GENERIC_READ; 00257 } 00258 00259 /* Handle the type flags */ 00260 if (dwPipeMode & PIPE_TYPE_MESSAGE) 00261 { 00262 WriteModeMessage = FILE_PIPE_MESSAGE_TYPE; 00263 } 00264 else 00265 { 00266 WriteModeMessage = FILE_PIPE_BYTE_STREAM_TYPE; 00267 } 00268 00269 /* Handle the mode flags */ 00270 if (dwPipeMode & PIPE_READMODE_MESSAGE) 00271 { 00272 ReadModeMessage = FILE_PIPE_MESSAGE_MODE; 00273 } 00274 else 00275 { 00276 ReadModeMessage = FILE_PIPE_BYTE_STREAM_MODE; 00277 } 00278 00279 /* Handle the blocking mode */ 00280 if (dwPipeMode & PIPE_NOWAIT) 00281 { 00282 NonBlocking = FILE_PIPE_COMPLETE_OPERATION; 00283 } 00284 else 00285 { 00286 NonBlocking = FILE_PIPE_QUEUE_OPERATION; 00287 } 00288 00289 /* Check if we have a timeout */ 00290 if (nDefaultTimeOut) 00291 { 00292 /* Convert the time to NT format */ 00293 DefaultTimeOut.QuadPart = UInt32x32To64(nDefaultTimeOut, -10000); 00294 } 00295 else 00296 { 00297 /* Use default timeout of 50 ms */ 00298 DefaultTimeOut.QuadPart = -500000; 00299 } 00300 00301 /* Now create the pipe */ 00302 Status = NtCreateNamedPipeFile(&PipeHandle, 00303 DesiredAccess, 00304 &ObjectAttributes, 00305 &Iosb, 00306 ShareAccess, 00307 FILE_OPEN_IF, 00308 CreateOptions, 00309 WriteModeMessage, 00310 ReadModeMessage, 00311 NonBlocking, 00312 nMaxInstances, 00313 nInBufferSize, 00314 nOutBufferSize, 00315 &DefaultTimeOut); 00316 00317 /* Normalize special error codes */ 00318 if ((Status == STATUS_INVALID_DEVICE_REQUEST) || 00319 (Status == STATUS_NOT_SUPPORTED)) 00320 { 00321 Status = STATUS_OBJECT_NAME_INVALID; 00322 } 00323 00324 /* Free the name */ 00325 RtlFreeHeap(RtlGetProcessHeap(), 00326 0, 00327 NamedPipeName.Buffer); 00328 00329 /* Check status */ 00330 if (!NT_SUCCESS(Status)) 00331 { 00332 /* Failed to create it */ 00333 WARN("NtCreateNamedPipe failed (Status %x)!\n", Status); 00334 BaseSetLastNTError (Status); 00335 return INVALID_HANDLE_VALUE; 00336 } 00337 00338 /* Return the handle */ 00339 return PipeHandle; 00340 } 00341 00342 00343 /* 00344 * @implemented 00345 */ 00346 BOOL 00347 WINAPI 00348 WaitNamedPipeA(LPCSTR lpNamedPipeName, 00349 DWORD nTimeOut) 00350 { 00351 BOOL r; 00352 UNICODE_STRING NameU; 00353 00354 /* Convert the name to Unicode */ 00355 Basep8BitStringToDynamicUnicodeString(&NameU, lpNamedPipeName); 00356 00357 /* Call the Unicode API */ 00358 r = WaitNamedPipeW(NameU.Buffer, nTimeOut); 00359 00360 /* Free the Unicode string */ 00361 RtlFreeUnicodeString(&NameU); 00362 00363 /* Return result */ 00364 return r; 00365 } 00366 00367 00368 /* 00369 * When NPFS will work properly, use this code instead. It is compatible with 00370 * Microsoft's NPFS.SYS. The main difference is that: 00371 * - This code actually respects the timeout instead of ignoring it! 00372 * - This code validates and creates the proper names for both UNC and local pipes 00373 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or 00374 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the 00375 * FILE_PIPE_WAIT_FOR_BUFFER structure. 00376 */ 00377 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS 00378 /* 00379 * @implemented 00380 */ 00381 BOOL 00382 WINAPI 00383 WaitNamedPipeW(LPCWSTR lpNamedPipeName, 00384 DWORD nTimeOut) 00385 { 00386 UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix; 00387 ULONG NameLength; 00388 ULONG i; 00389 PWCHAR p; 00390 ULONG Type; 00391 OBJECT_ATTRIBUTES ObjectAttributes; 00392 NTSTATUS Status; 00393 HANDLE FileHandle; 00394 IO_STATUS_BLOCK IoStatusBlock; 00395 ULONG WaitPipeInfoSize; 00396 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo; 00397 00398 /* Start by making a unicode string of the name */ 00399 TRACE("Sent path: %S\n", lpNamedPipeName); 00400 RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName); 00401 NameLength = NamedPipeName.Length / sizeof(WCHAR); 00402 00403 /* All slashes must become backslashes */ 00404 for (i = 0; i < NameLength; i++) 00405 { 00406 /* Check and convert */ 00407 if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\'; 00408 } 00409 00410 /* Find the path type of the name we were given */ 00411 NewName = NamedPipeName; 00412 Type = RtlDetermineDosPathNameType_U(lpNamedPipeName); 00413 00414 /* Check if this was a device path, ie : "\\.\pipe\name" */ 00415 if (Type == RtlPathTypeLocalDevice) 00416 { 00417 /* Make sure it's a valid prefix */ 00418 RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\"); 00419 RtlPrefixString((PANSI_STRING)&PipePrefix, (PANSI_STRING)&NewName, TRUE); 00420 00421 /* Move past it */ 00422 NewName.Buffer += 9; 00423 NewName.Length -= 9 * sizeof(WCHAR); 00424 00425 /* Initialize the Dos Devices name */ 00426 TRACE("NewName: %wZ\n", &NewName); 00427 RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\"); 00428 } 00429 else if (Type == RtlPathTypeRootLocalDevice) 00430 { 00431 /* The path is \\server\\pipe\name; find the pipename itself */ 00432 p = &NewName.Buffer[2]; 00433 00434 /* First loop to get past the server name */ 00435 do 00436 { 00437 /* Check if this is a backslash */ 00438 if (*p == L'\\') break; 00439 00440 /* Check next */ 00441 p++; 00442 } while (*p); 00443 00444 /* Now make sure the full name contains "pipe\" */ 00445 if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\")))) 00446 { 00447 /* Get to the pipe name itself now */ 00448 p += sizeof("pipe\\") - 1; 00449 } 00450 else 00451 { 00452 /* The name is invalid */ 00453 WARN("Invalid name!\n"); 00454 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD); 00455 return FALSE; 00456 } 00457 00458 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */ 00459 } 00460 else 00461 { 00462 WARN("Invalid path type\n"); 00463 BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD); 00464 return FALSE; 00465 } 00466 00467 /* Now calculate the total length of the structure and allocate it */ 00468 WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + 00469 NewName.Length; 00470 WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize); 00471 if (WaitPipeInfo == NULL) 00472 { 00473 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00474 return FALSE; 00475 } 00476 00477 /* Initialize the object attributes */ 00478 TRACE("Opening: %wZ\n", &DevicePath); 00479 InitializeObjectAttributes(&ObjectAttributes, 00480 &DevicePath, 00481 OBJ_CASE_INSENSITIVE, 00482 NULL, 00483 NULL); 00484 00485 /* Open the path */ 00486 Status = NtOpenFile(&FileHandle, 00487 FILE_READ_ATTRIBUTES | SYNCHRONIZE, 00488 &ObjectAttributes, 00489 &IoStatusBlock, 00490 FILE_SHARE_READ | FILE_SHARE_WRITE, 00491 FILE_SYNCHRONOUS_IO_NONALERT); 00492 if (!NT_SUCCESS(Status)) 00493 { 00494 /* Fail; couldn't open */ 00495 WARN("Status: %lx\n", Status); 00496 BaseSetLastNTError(Status); 00497 RtlFreeUnicodeString(&NamedPipeName); 00498 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo); 00499 return FALSE; 00500 } 00501 00502 /* Check what timeout we got */ 00503 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT) 00504 { 00505 /* Don't use a timeout */ 00506 WaitPipeInfo->TimeoutSpecified = FALSE; 00507 } 00508 else 00509 { 00510 /* Check if we should wait forever */ 00511 if (nTimeOut == NMPWAIT_WAIT_FOREVER) 00512 { 00513 /* Set the max */ 00514 WaitPipeInfo->Timeout.LowPart = 0; 00515 WaitPipeInfo->Timeout.HighPart = 0x80000000; 00516 } 00517 else 00518 { 00519 /* Convert to NT format */ 00520 WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut); 00521 } 00522 00523 /* In both cases, we do have a timeout */ 00524 WaitPipeInfo->TimeoutSpecified = TRUE; 00525 } 00526 00527 /* Set the length and copy the name */ 00528 WaitPipeInfo->NameLength = NewName.Length; 00529 RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length); 00530 00531 /* Get rid of the full name */ 00532 RtlFreeUnicodeString(&NamedPipeName); 00533 00534 /* Let NPFS know of our request */ 00535 Status = NtFsControlFile(FileHandle, 00536 NULL, 00537 NULL, 00538 NULL, 00539 &IoStatusBlock, 00540 FSCTL_PIPE_WAIT, 00541 WaitPipeInfo, 00542 WaitPipeInfoSize, 00543 NULL, 00544 0); 00545 00546 /* Free our pipe info data and close the handle */ 00547 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo); 00548 NtClose(FileHandle); 00549 00550 /* Check the status */ 00551 if (!NT_SUCCESS(Status)) 00552 { 00553 /* Failure to wait on the pipe */ 00554 WARN("Status: %lx\n", Status); 00555 BaseSetLastNTError (Status); 00556 return FALSE; 00557 } 00558 00559 /* Success */ 00560 return TRUE; 00561 } 00562 #else 00563 /* 00564 * @implemented 00565 */ 00566 BOOL 00567 WINAPI 00568 WaitNamedPipeW(LPCWSTR lpNamedPipeName, 00569 DWORD nTimeOut) 00570 { 00571 UNICODE_STRING NamedPipeName; 00572 NTSTATUS Status; 00573 OBJECT_ATTRIBUTES ObjectAttributes; 00574 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe; 00575 HANDLE FileHandle; 00576 IO_STATUS_BLOCK Iosb; 00577 00578 if (RtlDosPathNameToNtPathName_U(lpNamedPipeName, 00579 &NamedPipeName, 00580 NULL, 00581 NULL) == FALSE) 00582 { 00583 return FALSE; 00584 } 00585 00586 InitializeObjectAttributes(&ObjectAttributes, 00587 &NamedPipeName, 00588 OBJ_CASE_INSENSITIVE, 00589 NULL, 00590 NULL); 00591 Status = NtOpenFile(&FileHandle, 00592 FILE_READ_ATTRIBUTES | SYNCHRONIZE, 00593 &ObjectAttributes, 00594 &Iosb, 00595 FILE_SHARE_READ | FILE_SHARE_WRITE, 00596 FILE_SYNCHRONOUS_IO_NONALERT); 00597 if (!NT_SUCCESS(Status)) 00598 { 00599 BaseSetLastNTError(Status); 00600 RtlFreeUnicodeString(&NamedPipeName); 00601 return FALSE; 00602 } 00603 00604 /* Check what timeout we got */ 00605 if (nTimeOut == NMPWAIT_WAIT_FOREVER) 00606 { 00607 /* Don't use a timeout */ 00608 WaitPipe.TimeoutSpecified = FALSE; 00609 } 00610 else 00611 { 00612 /* Check if default */ 00613 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT) 00614 { 00615 /* Set it to 0 */ 00616 WaitPipe.Timeout.LowPart = 0; 00617 WaitPipe.Timeout.HighPart = 0; 00618 } 00619 else 00620 { 00621 /* Convert to NT format */ 00622 WaitPipe.Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut); 00623 } 00624 00625 /* In both cases, we do have a timeout */ 00626 WaitPipe.TimeoutSpecified = TRUE; 00627 } 00628 00629 Status = NtFsControlFile(FileHandle, 00630 NULL, 00631 NULL, 00632 NULL, 00633 &Iosb, 00634 FSCTL_PIPE_WAIT, 00635 &WaitPipe, 00636 sizeof(WaitPipe), 00637 NULL, 00638 0); 00639 NtClose(FileHandle); 00640 if (!NT_SUCCESS(Status)) 00641 { 00642 BaseSetLastNTError(Status); 00643 RtlFreeUnicodeString(&NamedPipeName); 00644 return FALSE; 00645 } 00646 00647 RtlFreeUnicodeString(&NamedPipeName); 00648 return TRUE; 00649 } 00650 #endif 00651 00652 00653 /* 00654 * @implemented 00655 */ 00656 BOOL 00657 WINAPI 00658 ConnectNamedPipe(IN HANDLE hNamedPipe, 00659 IN LPOVERLAPPED lpOverlapped) 00660 { 00661 NTSTATUS Status; 00662 00663 if (lpOverlapped != NULL) 00664 { 00665 PVOID ApcContext; 00666 00667 lpOverlapped->Internal = STATUS_PENDING; 00668 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped); 00669 00670 Status = NtFsControlFile(hNamedPipe, 00671 lpOverlapped->hEvent, 00672 NULL, 00673 ApcContext, 00674 (PIO_STATUS_BLOCK)lpOverlapped, 00675 FSCTL_PIPE_LISTEN, 00676 NULL, 00677 0, 00678 NULL, 00679 0); 00680 00681 /* return FALSE in case of failure and pending operations! */ 00682 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) 00683 { 00684 BaseSetLastNTError(Status); 00685 return FALSE; 00686 } 00687 } 00688 else 00689 { 00690 IO_STATUS_BLOCK Iosb; 00691 00692 Status = NtFsControlFile(hNamedPipe, 00693 NULL, 00694 NULL, 00695 NULL, 00696 &Iosb, 00697 FSCTL_PIPE_LISTEN, 00698 NULL, 00699 0, 00700 NULL, 00701 0); 00702 00703 /* wait in case operation is pending */ 00704 if (Status == STATUS_PENDING) 00705 { 00706 Status = NtWaitForSingleObject(hNamedPipe, 00707 FALSE, 00708 NULL); 00709 if (NT_SUCCESS(Status)) 00710 { 00711 Status = Iosb.Status; 00712 } 00713 } 00714 00715 if (!NT_SUCCESS(Status)) 00716 { 00717 BaseSetLastNTError(Status); 00718 return FALSE; 00719 } 00720 } 00721 00722 return TRUE; 00723 } 00724 00725 00726 /* 00727 * @implemented 00728 */ 00729 BOOL 00730 WINAPI 00731 SetNamedPipeHandleState(HANDLE hNamedPipe, 00732 LPDWORD lpMode, 00733 LPDWORD lpMaxCollectionCount, 00734 LPDWORD lpCollectDataTimeout) 00735 { 00736 IO_STATUS_BLOCK Iosb; 00737 NTSTATUS Status; 00738 00739 /* Check if the Mode is being changed */ 00740 if (lpMode) 00741 { 00742 FILE_PIPE_INFORMATION Settings; 00743 00744 /* Set the Completion Mode */ 00745 Settings.CompletionMode = (*lpMode & PIPE_NOWAIT) ? 00746 FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION; 00747 00748 /* Set the Read Mode */ 00749 Settings.ReadMode = (*lpMode & PIPE_READMODE_MESSAGE) ? 00750 FILE_PIPE_MESSAGE_MODE: FILE_PIPE_BYTE_STREAM_MODE; 00751 00752 /* Send the changes to the Driver */ 00753 Status = NtSetInformationFile(hNamedPipe, 00754 &Iosb, 00755 &Settings, 00756 sizeof(FILE_PIPE_INFORMATION), 00757 FilePipeInformation); 00758 if (!NT_SUCCESS(Status)) 00759 { 00760 BaseSetLastNTError(Status); 00761 return FALSE; 00762 } 00763 } 00764 00765 /* Check if the Collection count or Timeout are being changed */ 00766 if (lpMaxCollectionCount || lpCollectDataTimeout) 00767 { 00768 FILE_PIPE_REMOTE_INFORMATION RemoteSettings; 00769 00770 /* Setting one without the other would delete it, so we read old one */ 00771 if (!lpMaxCollectionCount || !lpCollectDataTimeout) 00772 { 00773 Status = NtQueryInformationFile(hNamedPipe, 00774 &Iosb, 00775 &RemoteSettings, 00776 sizeof(FILE_PIPE_REMOTE_INFORMATION), 00777 FilePipeRemoteInformation); 00778 if (!NT_SUCCESS(Status)) 00779 { 00780 BaseSetLastNTError(Status); 00781 return FALSE; 00782 } 00783 } 00784 00785 /* Now set the new settings */ 00786 RemoteSettings.MaximumCollectionCount = (lpMaxCollectionCount) ? 00787 *lpMaxCollectionCount : 00788 RemoteSettings.MaximumCollectionCount; 00789 if (lpCollectDataTimeout) 00790 { 00791 /* Convert it to Quad */ 00792 RemoteSettings.CollectDataTime.QuadPart = 00793 -(LONGLONG)UInt32x32To64(10000, *lpCollectDataTimeout); 00794 } 00795 00796 /* Tell the driver to change them */ 00797 Status = NtSetInformationFile(hNamedPipe, 00798 &Iosb, 00799 &RemoteSettings, 00800 sizeof(FILE_PIPE_REMOTE_INFORMATION), 00801 FilePipeRemoteInformation); 00802 if (!NT_SUCCESS(Status)) 00803 { 00804 BaseSetLastNTError(Status); 00805 return FALSE; 00806 } 00807 } 00808 00809 return TRUE; 00810 } 00811 00812 00813 /* 00814 * @implemented 00815 */ 00816 BOOL 00817 WINAPI 00818 CallNamedPipeA(LPCSTR lpNamedPipeName, 00819 LPVOID lpInBuffer, 00820 DWORD nInBufferSize, 00821 LPVOID lpOutBuffer, 00822 DWORD nOutBufferSize, 00823 LPDWORD lpBytesRead, 00824 DWORD nTimeOut) 00825 { 00826 PUNICODE_STRING PipeName = &NtCurrentTeb()->StaticUnicodeString; 00827 ANSI_STRING AnsiPipe; 00828 00829 /* Initialize the string as ANSI_STRING and convert to Unicode */ 00830 RtlInitAnsiString(&AnsiPipe, (LPSTR)lpNamedPipeName); 00831 RtlAnsiStringToUnicodeString(PipeName, &AnsiPipe, FALSE); 00832 00833 /* Call the Unicode function */ 00834 return CallNamedPipeW(PipeName->Buffer, 00835 lpInBuffer, 00836 nInBufferSize, 00837 lpOutBuffer, 00838 nOutBufferSize, 00839 lpBytesRead, 00840 nTimeOut); 00841 } 00842 00843 00844 /* 00845 * @implemented 00846 */ 00847 BOOL 00848 WINAPI 00849 CallNamedPipeW(LPCWSTR lpNamedPipeName, 00850 LPVOID lpInBuffer, 00851 DWORD nInBufferSize, 00852 LPVOID lpOutBuffer, 00853 DWORD nOutBufferSize, 00854 LPDWORD lpBytesRead, 00855 DWORD nTimeOut) 00856 { 00857 HANDLE hPipe; 00858 BOOL bRetry = TRUE; 00859 BOOL bError; 00860 DWORD dwPipeMode; 00861 00862 while (TRUE) 00863 { 00864 /* Try creating it */ 00865 hPipe = CreateFileW(lpNamedPipeName, 00866 GENERIC_READ | GENERIC_WRITE, 00867 FILE_SHARE_READ | FILE_SHARE_WRITE, 00868 NULL, 00869 OPEN_EXISTING, 00870 FILE_ATTRIBUTE_NORMAL, 00871 NULL); 00872 00873 /* Success, break out */ 00874 if (hPipe != INVALID_HANDLE_VALUE) 00875 break; 00876 00877 /* Already tried twice, give up */ 00878 if (bRetry == FALSE) 00879 return FALSE; 00880 00881 /* Wait on it */ 00882 WaitNamedPipeW(lpNamedPipeName, nTimeOut); 00883 00884 /* Get ready to try again */ 00885 bRetry = FALSE; 00886 } 00887 00888 /* Set the pipe mode */ 00889 dwPipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; 00890 bError = SetNamedPipeHandleState(hPipe, &dwPipeMode, NULL, NULL); 00891 if (!bError) 00892 { 00893 /* Couldn't change state, fail */ 00894 CloseHandle(hPipe); 00895 return FALSE; 00896 } 00897 00898 /* Do the transact */ 00899 bError = TransactNamedPipe(hPipe, 00900 lpInBuffer, 00901 nInBufferSize, 00902 lpOutBuffer, 00903 nOutBufferSize, 00904 lpBytesRead, 00905 NULL); 00906 00907 /* Close the handle */ 00908 CloseHandle(hPipe); 00909 00910 return bError; 00911 } 00912 00913 00914 /* 00915 * @implemented 00916 */ 00917 BOOL 00918 WINAPI 00919 DisconnectNamedPipe(HANDLE hNamedPipe) 00920 { 00921 IO_STATUS_BLOCK Iosb; 00922 NTSTATUS Status; 00923 00924 /* Send the FSCTL to the driver */ 00925 Status = NtFsControlFile(hNamedPipe, 00926 NULL, 00927 NULL, 00928 NULL, 00929 &Iosb, 00930 FSCTL_PIPE_DISCONNECT, 00931 NULL, 00932 0, 00933 NULL, 00934 0); 00935 if (Status == STATUS_PENDING) 00936 { 00937 /* Wait on NPFS to finish and get updated status */ 00938 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL); 00939 if (NT_SUCCESS(Status)) 00940 Status = Iosb.Status; 00941 } 00942 00943 /* Check for error */ 00944 if (!NT_SUCCESS(Status)) 00945 { 00946 /* Fail */ 00947 BaseSetLastNTError(Status); 00948 return FALSE; 00949 } 00950 00951 return TRUE; 00952 } 00953 00954 00955 /* 00956 * @unimplemented 00957 */ 00958 BOOL 00959 WINAPI 00960 GetNamedPipeHandleStateW(HANDLE hNamedPipe, 00961 LPDWORD lpState, 00962 LPDWORD lpCurInstances, 00963 LPDWORD lpMaxCollectionCount, 00964 LPDWORD lpCollectDataTimeout, 00965 LPWSTR lpUserName, 00966 DWORD nMaxUserNameSize) 00967 { 00968 IO_STATUS_BLOCK StatusBlock; 00969 NTSTATUS Status; 00970 00971 if (lpState != NULL) 00972 { 00973 FILE_PIPE_INFORMATION PipeInfo; 00974 00975 Status = NtQueryInformationFile(hNamedPipe, 00976 &StatusBlock, 00977 &PipeInfo, 00978 sizeof(FILE_PIPE_INFORMATION), 00979 FilePipeInformation); 00980 if (!NT_SUCCESS(Status)) 00981 { 00982 BaseSetLastNTError(Status); 00983 return FALSE; 00984 } 00985 00986 *lpState = ((PipeInfo.CompletionMode != FILE_PIPE_QUEUE_OPERATION) ? PIPE_NOWAIT : PIPE_WAIT); 00987 *lpState |= ((PipeInfo.ReadMode != FILE_PIPE_BYTE_STREAM_MODE) ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE); 00988 } 00989 00990 if(lpCurInstances != NULL) 00991 { 00992 FILE_PIPE_LOCAL_INFORMATION LocalInfo; 00993 00994 Status = NtQueryInformationFile(hNamedPipe, 00995 &StatusBlock, 00996 &LocalInfo, 00997 sizeof(FILE_PIPE_LOCAL_INFORMATION), 00998 FilePipeLocalInformation); 00999 if (!NT_SUCCESS(Status)) 01000 { 01001 BaseSetLastNTError(Status); 01002 return FALSE; 01003 } 01004 01005 *lpCurInstances = min(LocalInfo.CurrentInstances, PIPE_UNLIMITED_INSTANCES); 01006 } 01007 01008 if (lpMaxCollectionCount != NULL || lpCollectDataTimeout != NULL) 01009 { 01010 FILE_PIPE_REMOTE_INFORMATION RemoteInfo; 01011 01012 Status = NtQueryInformationFile(hNamedPipe, 01013 &StatusBlock, 01014 &RemoteInfo, 01015 sizeof(FILE_PIPE_REMOTE_INFORMATION), 01016 FilePipeRemoteInformation); 01017 if (!NT_SUCCESS(Status)) 01018 { 01019 BaseSetLastNTError(Status); 01020 return FALSE; 01021 } 01022 01023 if (lpMaxCollectionCount != NULL) 01024 { 01025 *lpMaxCollectionCount = RemoteInfo.MaximumCollectionCount; 01026 } 01027 01028 if(lpCollectDataTimeout != NULL) 01029 { 01030 /* FIXME */ 01031 *lpCollectDataTimeout = 0; 01032 } 01033 } 01034 01035 if (lpUserName != NULL) 01036 { 01037 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and 01038 retreive the user name with GetUserName(), revert the impersonation 01039 and finally restore the thread token */ 01040 } 01041 01042 return TRUE; 01043 } 01044 01045 01046 /* 01047 * @implemented 01048 */ 01049 BOOL 01050 WINAPI 01051 GetNamedPipeHandleStateA(HANDLE hNamedPipe, 01052 LPDWORD lpState, 01053 LPDWORD lpCurInstances, 01054 LPDWORD lpMaxCollectionCount, 01055 LPDWORD lpCollectDataTimeout, 01056 LPSTR lpUserName, 01057 DWORD nMaxUserNameSize) 01058 { 01059 UNICODE_STRING UserNameW = { 0, 0, NULL }; 01060 ANSI_STRING UserNameA; 01061 BOOL Ret; 01062 01063 if(lpUserName != NULL) 01064 { 01065 UserNameW.MaximumLength = (USHORT)nMaxUserNameSize * sizeof(WCHAR); 01066 UserNameW.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW.MaximumLength); 01067 if (UserNameW.Buffer == NULL) 01068 { 01069 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01070 return FALSE; 01071 } 01072 01073 UserNameA.Buffer = lpUserName; 01074 UserNameA.Length = 0; 01075 UserNameA.MaximumLength = (USHORT)nMaxUserNameSize; 01076 } 01077 01078 Ret = GetNamedPipeHandleStateW(hNamedPipe, 01079 lpState, 01080 lpCurInstances, 01081 lpMaxCollectionCount, 01082 lpCollectDataTimeout, 01083 UserNameW.Buffer, 01084 nMaxUserNameSize); 01085 if (Ret && lpUserName != NULL) 01086 { 01087 NTSTATUS Status; 01088 01089 RtlInitUnicodeString(&UserNameW, UserNameW.Buffer); 01090 Status = RtlUnicodeStringToAnsiString(&UserNameA, &UserNameW, FALSE); 01091 if (!NT_SUCCESS(Status)) 01092 { 01093 BaseSetLastNTError(Status); 01094 Ret = FALSE; 01095 } 01096 } 01097 01098 if (UserNameW.Buffer != NULL) 01099 { 01100 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW.Buffer); 01101 } 01102 01103 return Ret; 01104 } 01105 01106 01107 /* 01108 * @implemented 01109 */ 01110 BOOL 01111 WINAPI 01112 GetNamedPipeInfo(HANDLE hNamedPipe, 01113 LPDWORD lpFlags, 01114 LPDWORD lpOutBufferSize, 01115 LPDWORD lpInBufferSize, 01116 LPDWORD lpMaxInstances) 01117 { 01118 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation; 01119 IO_STATUS_BLOCK StatusBlock; 01120 NTSTATUS Status; 01121 01122 Status = NtQueryInformationFile(hNamedPipe, 01123 &StatusBlock, 01124 &PipeLocalInformation, 01125 sizeof(FILE_PIPE_LOCAL_INFORMATION), 01126 FilePipeLocalInformation); 01127 if (!NT_SUCCESS(Status)) 01128 { 01129 BaseSetLastNTError(Status); 01130 return FALSE; 01131 } 01132 01133 if (lpFlags != NULL) 01134 { 01135 *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END; 01136 *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE; 01137 } 01138 01139 if (lpOutBufferSize != NULL) 01140 *lpOutBufferSize = PipeLocalInformation.OutboundQuota; 01141 01142 if (lpInBufferSize != NULL) 01143 *lpInBufferSize = PipeLocalInformation.InboundQuota; 01144 01145 if (lpMaxInstances != NULL) 01146 { 01147 if (PipeLocalInformation.MaximumInstances >= 255) 01148 *lpMaxInstances = PIPE_UNLIMITED_INSTANCES; 01149 else 01150 *lpMaxInstances = PipeLocalInformation.MaximumInstances; 01151 } 01152 01153 return TRUE; 01154 } 01155 01156 01157 /* 01158 * @implemented 01159 */ 01160 BOOL 01161 WINAPI 01162 PeekNamedPipe(HANDLE hNamedPipe, 01163 LPVOID lpBuffer, 01164 DWORD nBufferSize, 01165 LPDWORD lpBytesRead, 01166 LPDWORD lpTotalBytesAvail, 01167 LPDWORD lpBytesLeftThisMessage) 01168 { 01169 PFILE_PIPE_PEEK_BUFFER Buffer; 01170 IO_STATUS_BLOCK Iosb; 01171 ULONG BufferSize; 01172 ULONG BytesRead; 01173 NTSTATUS Status; 01174 01175 /* Calculate the buffer space that we'll need and allocate it */ 01176 BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER); 01177 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize); 01178 if (Buffer == NULL) 01179 { 01180 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01181 return FALSE; 01182 } 01183 01184 /* Tell the driver to seek */ 01185 Status = NtFsControlFile(hNamedPipe, 01186 NULL, 01187 NULL, 01188 NULL, 01189 &Iosb, 01190 FSCTL_PIPE_PEEK, 01191 NULL, 01192 0, 01193 Buffer, 01194 BufferSize); 01195 if (Status == STATUS_PENDING) 01196 { 01197 /* Wait for npfs to be done, and update the status */ 01198 Status = NtWaitForSingleObject(hNamedPipe, FALSE, NULL); 01199 if (NT_SUCCESS(Status)) 01200 Status = Iosb.Status; 01201 } 01202 01203 /* Overflow is success for us */ 01204 if (Status == STATUS_BUFFER_OVERFLOW) 01205 Status = STATUS_SUCCESS; 01206 01207 /* If we failed */ 01208 if (!NT_SUCCESS(Status)) 01209 { 01210 /* Free the buffer and return failure */ 01211 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 01212 BaseSetLastNTError(Status); 01213 return FALSE; 01214 } 01215 01216 /* Check if caller requested bytes available */ 01217 if (lpTotalBytesAvail) 01218 *lpTotalBytesAvail = Buffer->ReadDataAvailable; 01219 01220 /* Calculate the bytes returned, minus our structure overhead */ 01221 BytesRead = (ULONG)(Iosb.Information - 01222 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])); 01223 01224 /* Check if caller requested bytes read */ 01225 if (lpBytesRead) 01226 { 01227 /* Return the bytes read */ 01228 *lpBytesRead = BytesRead; 01229 } 01230 01231 /* Check if caller requested bytes left */ 01232 if (lpBytesLeftThisMessage) 01233 { 01234 /* Calculate total minus what we returned and our structure overhead */ 01235 *lpBytesLeftThisMessage = Buffer->MessageLength - BytesRead; 01236 } 01237 01238 /* Check if the caller wanted to see the actual data */ 01239 if (lpBuffer) 01240 { 01241 /* Give him what he wants */ 01242 RtlCopyMemory(lpBuffer, 01243 Buffer->Data, 01244 BytesRead); 01245 } 01246 01247 /* Free the buffer */ 01248 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 01249 01250 return TRUE; 01251 } 01252 01253 01254 /* 01255 * @implemented 01256 */ 01257 BOOL 01258 WINAPI 01259 TransactNamedPipe(IN HANDLE hNamedPipe, 01260 IN LPVOID lpInBuffer, 01261 IN DWORD nInBufferSize, 01262 OUT LPVOID lpOutBuffer, 01263 IN DWORD nOutBufferSize, 01264 OUT LPDWORD lpBytesRead OPTIONAL, 01265 IN LPOVERLAPPED lpOverlapped OPTIONAL) 01266 { 01267 NTSTATUS Status; 01268 01269 if (lpBytesRead != NULL) 01270 { 01271 *lpBytesRead = 0; 01272 } 01273 01274 if (lpOverlapped != NULL) 01275 { 01276 PVOID ApcContext; 01277 01278 ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped); 01279 lpOverlapped->Internal = STATUS_PENDING; 01280 01281 Status = NtFsControlFile(hNamedPipe, 01282 lpOverlapped->hEvent, 01283 NULL, 01284 ApcContext, 01285 (PIO_STATUS_BLOCK)lpOverlapped, 01286 FSCTL_PIPE_TRANSCEIVE, 01287 lpInBuffer, 01288 nInBufferSize, 01289 lpOutBuffer, 01290 nOutBufferSize); 01291 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) 01292 { 01293 BaseSetLastNTError(Status); 01294 return FALSE; 01295 } 01296 01297 if (lpBytesRead != NULL) 01298 { 01299 *lpBytesRead = lpOverlapped->InternalHigh; 01300 } 01301 } 01302 else 01303 { 01304 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */ 01305 IO_STATUS_BLOCK Iosb; 01306 01307 Status = NtFsControlFile(hNamedPipe, 01308 NULL, 01309 NULL, 01310 NULL, 01311 &Iosb, 01312 FSCTL_PIPE_TRANSCEIVE, 01313 lpInBuffer, 01314 nInBufferSize, 01315 lpOutBuffer, 01316 nOutBufferSize); 01317 if (Status == STATUS_PENDING) 01318 { 01319 Status = NtWaitForSingleObject(hNamedPipe, 01320 FALSE, 01321 NULL); 01322 if (NT_SUCCESS(Status)) 01323 Status = Iosb.Status; 01324 } 01325 01326 if (NT_SUCCESS(Status)) 01327 { 01328 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't 01329 check that case either and crashes (only after the operation 01330 completed) */ 01331 *lpBytesRead = Iosb.Information; 01332 } 01333 else 01334 { 01335 BaseSetLastNTError(Status); 01336 return FALSE; 01337 } 01338 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */ 01339 DWORD nActualBytes; 01340 01341 while (0 != nInBufferSize && 01342 WriteFile(hNamedPipe, lpInBuffer, nInBufferSize, &nActualBytes, 01343 NULL)) 01344 { 01345 lpInBuffer = (LPVOID)((char *) lpInBuffer + nActualBytes); 01346 nInBufferSize -= nActualBytes; 01347 } 01348 01349 if (0 != nInBufferSize) 01350 { 01351 /* Must have dropped out of the while 'cause WriteFile failed */ 01352 return FALSE; 01353 } 01354 01355 if (!ReadFile(hNamedPipe, lpOutBuffer, nOutBufferSize, &nActualBytes, 01356 NULL)) 01357 { 01358 return FALSE; 01359 } 01360 01361 if (NULL != lpBytesRead) 01362 { 01363 *lpBytesRead = nActualBytes; 01364 } 01365 #endif 01366 } 01367 01368 return TRUE; 01369 } 01370 01371 /* EOF */ Generated on Mon May 28 2012 04:24:05 for ReactOS by
1.7.6.1
|