From: Alex Ionescu Date: Tue, 8 Nov 2005 21:07:11 +0000 (+0000) Subject: - Implement proper version of WaitNamedPipeW to be used when NPFS will be modified... X-Git-Tag: backups/ros-branch-0_2_9@19949~832 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=7bccddff969e98cc893dd352109d56b92ac3ad7e;hp=eb9906dcc21abcdcd4a5c4cd26ff1748be64e869 - Implement proper version of WaitNamedPipeW to be used when NPFS will be modified to work as documented. Define USING_PROPER_NPFS_WAIT_SEMANTICS if you want to use Windows NPFS svn path=/trunk/; revision=19067 --- diff --git a/reactos/lib/kernel32/file/npipe.c b/reactos/lib/kernel32/file/npipe.c index f926dc4ae99..1143236f86e 100644 --- a/reactos/lib/kernel32/file/npipe.c +++ b/reactos/lib/kernel32/file/npipe.c @@ -199,7 +199,195 @@ WaitNamedPipeA(LPCSTR lpNamedPipeName, return(r); } +/* + * When NPFS will work properly, use this code instead. It is compatible with + * Microsoft's NPFS.SYS. The main difference is that: + * - This code actually respects the timeout instead of ignoring it! + * - This code validates and creates the proper names for both UNC and local pipes + * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or + * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the + * FILE_PIPE_WAIT_FOR_BUFFER structure. + */ +#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS +/* + * @implemented + */ +BOOL +WINAPI +WaitNamedPipeW(LPCWSTR lpNamedPipeName, + DWORD nTimeOut) +{ + UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix; + ULONG NameLength; + ULONG i; + PWCHAR p; + ULONG Type; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE FileHandle; + IO_STATUS_BLOCK IoStatusBlock; + ULONG WaitPipeInfoSize; + PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo; + + /* Start by making a unicode string of the name */ + DPRINT("Sent path: %S\n", lpNamedPipeName); + RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName); + NameLength = NamedPipeName.Length / sizeof(WCHAR); + + /* All slashes must become backslashes */ + for (i = 0; i < NameLength; i++) + { + /* Check and convert */ + if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\'; + } + + /* Find the path type of the name we were given */ + NewName = NamedPipeName; + Type = RtlDetermineDosPathNameType_U(lpNamedPipeName); + + /* Check if this was a device path, ie : "\\.\pipe\name" */ + if (Type == DEVICE_PATH) + { + /* Make sure it's a valid prefix */ + RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\"); + RtlPrefixString((PANSI_STRING)&PipePrefix, (PANSI_STRING)&NewName, TRUE); + + /* Move past it */ + NewName.Buffer += 9; + NewName.Length -= 9 * sizeof(WCHAR); + + /* Initialize the Dos Devices name */ + DPRINT("NewName: %wZ\n", &NewName); + RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\"); + } + else if (Type == UNC_PATH) + { + /* The path is \\server\\pipe\name; find the pipename itself */ + p = &NewName.Buffer[2]; + + /* First loop to get past the server name */ + do + { + /* Check if this is a backslash */ + if (*p == L'\\') break; + + /* Check next */ + p++; + } while (*p); + + /* Now make sure the full name contains "pipe\" */ + if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\")))) + { + /* Get to the pipe name itself now */ + p += sizeof("pipe\\") - 1; + } + else + { + /* The name is invalid */ + DPRINT1("Invalid name!\n"); + SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD); + return FALSE; + } + + /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */ + } + else + { + DPRINT1("Invalid path type\n"); + SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD); + return FALSE; + } + + /* Initialize the object attributes */ + DPRINT("Opening: %wZ\n", &DevicePath); + InitializeObjectAttributes(&ObjectAttributes, + &DevicePath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Open the path */ + Status = NtOpenFile(&FileHandle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + { + /* Fail; couldn't open */ + DPRINT1("Status: %lx\n", Status); + SetLastErrorByStatus(Status); + RtlFreeUnicodeString(&NamedPipeName); + return(FALSE); + } + /* Now calculate the total length of the structure and allocate it */ + WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + + NewName.Length; + WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize); + + /* Check what timeout we got */ + if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT) + { + /* Don't use a timeout */ + WaitPipeInfo->TimeoutSpecified = FALSE; + } + else + { + /* Check if we should wait forever */ + if (nTimeOut == NMPWAIT_WAIT_FOREVER) + { + /* Set the max */ + WaitPipeInfo->Timeout.LowPart = 0; + WaitPipeInfo->Timeout.HighPart = 0x80000000; + } + else + { + /* Convert to NT format */ + WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut); + } + + /* In both cases, we do have a timeout */ + WaitPipeInfo->TimeoutSpecified = FALSE; + } + + /* Set the length and copy the name */ + WaitPipeInfo->NameLength = NewName.Length; + RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length); + + /* Get rid of the full name */ + RtlFreeUnicodeString(&NamedPipeName); + + /* Let NPFS know of our request */ + Status = NtFsControlFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + FSCTL_PIPE_WAIT, + WaitPipeInfo, + WaitPipeInfoSize, + NULL, + 0); + + /* Free our pipe info data and close the handle */ + RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo); + NtClose(FileHandle); + + /* Check the status */ + if (!NT_SUCCESS(Status)) + { + /* Failure to wait on the pipe */ + DPRINT1("Status: %lx\n", Status); + SetLastErrorByStatus (Status); + return FALSE; + } + + /* Success */ + return TRUE; +} +#else /* * @implemented */ @@ -262,7 +450,7 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName, return(TRUE); } - +#endif /* * @implemented @@ -335,7 +523,6 @@ ConnectNamedPipe(IN HANDLE hNamedPipe, return TRUE; } - /* * @implemented */