From 23c4a2e25ff93005ad1a2dd3aef10ae26c2ea2e2 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sun, 1 Sep 2013 10:16:29 +0000 Subject: [PATCH] [NPFS/KERNEL32] * Back out r59915 for a moment so we can use Patchbot. svn path=/trunk/; revision=59934 --- .../dll/win32/kernel32/client/file/npipe.c | 103 ++++++++++++++ reactos/drivers/filesystems/npfs/create.c | 126 ++++++++++++------ reactos/drivers/filesystems/npfs/fsctrl.c | 122 ++++++++++++++++- 3 files changed, 308 insertions(+), 43 deletions(-) diff --git a/reactos/dll/win32/kernel32/client/file/npipe.c b/reactos/dll/win32/kernel32/client/file/npipe.c index ff61054c5e0..1844ef4a028 100644 --- a/reactos/dll/win32/kernel32/client/file/npipe.c +++ b/reactos/dll/win32/kernel32/client/file/npipe.c @@ -14,6 +14,8 @@ #include DEBUG_CHANNEL(kernel32file); +//#define USING_PROPER_NPFS_WAIT_SEMANTICS + /* GLOBALS ********************************************************************/ LONG ProcessPipeId; @@ -362,6 +364,17 @@ 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 */ @@ -546,6 +559,96 @@ WaitNamedPipeW(LPCWSTR lpNamedPipeName, /* Success */ return TRUE; } +#else +/* + * @implemented + */ +BOOL +WINAPI +WaitNamedPipeW(LPCWSTR lpNamedPipeName, + DWORD nTimeOut) +{ + UNICODE_STRING NamedPipeName; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + FILE_PIPE_WAIT_FOR_BUFFER WaitPipe; + HANDLE FileHandle; + IO_STATUS_BLOCK Iosb; + + if (RtlDosPathNameToNtPathName_U(lpNamedPipeName, + &NamedPipeName, + NULL, + NULL) == FALSE) + { + return FALSE; + } + + InitializeObjectAttributes(&ObjectAttributes, + &NamedPipeName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenFile(&FileHandle, + FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &ObjectAttributes, + &Iosb, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + RtlFreeUnicodeString(&NamedPipeName); + return FALSE; + } + + /* Check what timeout we got */ + if (nTimeOut == NMPWAIT_WAIT_FOREVER) + { + /* Don't use a timeout */ + WaitPipe.TimeoutSpecified = FALSE; + } + else + { + /* Check if default */ + if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT) + { + /* Set it to 0 */ + WaitPipe.Timeout.LowPart = 0; + WaitPipe.Timeout.HighPart = 0; + } + else + { + /* Convert to NT format */ + WaitPipe.Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut); + } + + /* In both cases, we do have a timeout */ + WaitPipe.TimeoutSpecified = TRUE; + } + + Status = NtFsControlFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + FSCTL_PIPE_WAIT, + &WaitPipe, + sizeof(WaitPipe), + NULL, + 0); + NtClose(FileHandle); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + RtlFreeUnicodeString(&NamedPipeName); + return FALSE; + } + + RtlFreeUnicodeString(&NamedPipeName); + return TRUE; +} +#endif + /* * @implemented diff --git a/reactos/drivers/filesystems/npfs/create.c b/reactos/drivers/filesystems/npfs/create.c index 7114b986a68..abdfe5e38d6 100644 --- a/reactos/drivers/filesystems/npfs/create.c +++ b/reactos/drivers/filesystems/npfs/create.c @@ -13,6 +13,8 @@ #define NDEBUG #include +//#define USING_PROPER_NPFS_WAIT_SEMANTICS + /* FUNCTIONS *****************************************************************/ VOID @@ -249,6 +251,10 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject, PNPFS_CCB ServerCcb = NULL; PNPFS_VCB Vcb; NTSTATUS Status; +#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS + ACCESS_MASK DesiredAccess; + BOOLEAN SpecialAccess; +#endif DPRINT("NpfsCreate(DeviceObject %p Irp %p)\n", DeviceObject, Irp); @@ -257,12 +263,23 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject, FileObject = IoStack->FileObject; RelatedFileObject = FileObject->RelatedFileObject; FileName = &FileObject->FileName; +#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS + DesiredAccess = IoStack->Parameters.CreatePipe.SecurityContext->DesiredAccess; +#endif DPRINT("FileObject %p\n", FileObject); DPRINT("FileName %wZ\n", &FileObject->FileName); Irp->IoStatus.Information = 0; +#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS + SpecialAccess = ((DesiredAccess & SPECIFIC_RIGHTS_ALL) == FILE_READ_ATTRIBUTES); + if (SpecialAccess) + { + DPRINT("NpfsCreate() open client end for special use!\n"); + } +#endif + DPRINT("FileName->Length: %hu RelatedFileObject: %p\n", FileName->Length, RelatedFileObject); /* Open the file system */ @@ -336,7 +353,11 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject, ClientCcb->FileObject = FileObject; ClientCcb->Thread = (struct ETHREAD *)Irp->Tail.Overlay.Thread; ClientCcb->PipeEnd = FILE_PIPE_CLIENT_END; +#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS + ClientCcb->PipeState = SpecialAccess ? 0 : FILE_PIPE_DISCONNECTED_STATE; +#else ClientCcb->PipeState = FILE_PIPE_DISCONNECTED_STATE; +#endif InitializeListHead(&ClientCcb->ReadRequestListHead); DPRINT("CCB: %p\n", ClientCcb); @@ -377,62 +398,85 @@ NpfsCreate(PDEVICE_OBJECT DeviceObject, /* * Step 3. Search for listening server CCB. */ - /* - * WARNING: Point of no return! Once we get the server CCB it's - * possible that we completed a wait request and so we have to - * complete even this request. - */ - - ServerCcb = NpfsFindListeningServerInstance(Fcb); - if (ServerCcb == NULL) +#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS + if (!SpecialAccess) { - PLIST_ENTRY CurrentEntry; - PNPFS_CCB Ccb; - +#endif /* - * If no waiting server CCB was found then try to pick - * one of the listing server CCB on the pipe. + * WARNING: Point of no return! Once we get the server CCB it's + * possible that we completed a wait request and so we have to + * complete even this request. */ - CurrentEntry = Fcb->ServerCcbListHead.Flink; - while (CurrentEntry != &Fcb->ServerCcbListHead) + ServerCcb = NpfsFindListeningServerInstance(Fcb); + if (ServerCcb == NULL) { - Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry); - if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE) + PLIST_ENTRY CurrentEntry; + PNPFS_CCB Ccb; + + /* + * If no waiting server CCB was found then try to pick + * one of the listing server CCB on the pipe. + */ + + CurrentEntry = Fcb->ServerCcbListHead.Flink; + while (CurrentEntry != &Fcb->ServerCcbListHead) { - ServerCcb = Ccb; - break; + Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry); + if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE) + { + ServerCcb = Ccb; + break; + } + CurrentEntry = CurrentEntry->Flink; } - CurrentEntry = CurrentEntry->Flink; - } - /* - * No one is listening to me?! I'm so lonely... :( - */ + /* + * No one is listening to me?! I'm so lonely... :( + */ - if (ServerCcb == NULL) - { - /* Not found, bail out with error for FILE_OPEN requests. */ - DPRINT("No listening server CCB found!\n"); - if (ClientCcb->Data) + if (ServerCcb == NULL) { - ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA); - } + /* Not found, bail out with error for FILE_OPEN requests. */ + DPRINT("No listening server CCB found!\n"); + if (ClientCcb->Data) + { + ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA); + } - NpfsDereferenceCcb(ClientCcb); - KeUnlockMutex(&Fcb->CcbListLock); - NpfsDereferenceFcb(Fcb); - Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_OBJECT_NAME_NOT_FOUND; + NpfsDereferenceCcb(ClientCcb); + KeUnlockMutex(&Fcb->CcbListLock); + NpfsDereferenceFcb(Fcb); + Irp->IoStatus.Status = STATUS_OBJECT_NAME_NOT_FOUND; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_OBJECT_NAME_NOT_FOUND; + } } + else + { + /* Signal the server thread and remove it from the waiter list */ + /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */ + NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb); + } +#ifndef USING_PROPER_NPFS_WAIT_SEMANTICS } - else + else if (IsListEmpty(&Fcb->ServerCcbListHead)) { - /* Signal the server thread and remove it from the waiter list */ - /* FIXME: Merge this with the NpfsFindListeningServerInstance routine. */ - NpfsSignalAndRemoveListeningServerInstance(Fcb, ServerCcb); + DPRINT("No server fcb found!\n"); + + if (ClientCcb->Data) + { + ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA); + } + + NpfsDereferenceCcb(ClientCcb); + KeUnlockMutex(&Fcb->CcbListLock); + NpfsDereferenceFcb(Fcb); + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_UNSUCCESSFUL; } +#endif /* * Step 4. Add the client CCB to a list and connect it if possible. diff --git a/reactos/drivers/filesystems/npfs/fsctrl.c b/reactos/drivers/filesystems/npfs/fsctrl.c index 09870e98966..ce68432c920 100644 --- a/reactos/drivers/filesystems/npfs/fsctrl.c +++ b/reactos/drivers/filesystems/npfs/fsctrl.c @@ -15,6 +15,8 @@ #define NDEBUG #include +//#define USING_PROPER_NPFS_WAIT_SEMANTICS + /* FUNCTIONS *****************************************************************/ static DRIVER_CANCEL NpfsListeningCancelRoutine; @@ -317,9 +319,109 @@ NpfsDisconnectPipe(PNPFS_CCB Ccb) return Status; } -NTSTATUS +static NTSTATUS NpfsWaitPipe(PIRP Irp, PNPFS_CCB Ccb) +{ + PLIST_ENTRY current_entry; + PNPFS_FCB Fcb; + PNPFS_CCB ServerCcb; + PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe; + PLARGE_INTEGER TimeOut; + NTSTATUS Status; + PEXTENDED_IO_STACK_LOCATION IoStack; + PFILE_OBJECT FileObject; + PNPFS_VCB Vcb; + + IoStack = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp); + ASSERT(IoStack); + FileObject = IoStack->FileObject; + ASSERT(FileObject); + + DPRINT("Waiting on Pipe %wZ\n", &FileObject->FileName); + + WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer; + + ASSERT(Ccb->Fcb); + ASSERT(Ccb->Fcb->Vcb); + + /* Get the VCB */ + Vcb = Ccb->Fcb->Vcb; + + /* Lock the pipe list */ + KeLockMutex(&Vcb->PipeListLock); + + /* File a pipe with the given name */ + Fcb = NpfsFindPipe(Vcb, + &FileObject->FileName); + + /* Unlock the pipe list */ + KeUnlockMutex(&Vcb->PipeListLock); + + /* Fail if not pipe was found */ + if (Fcb == NULL) + { + DPRINT("No pipe found!\n"); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* search for listening server */ + current_entry = Fcb->ServerCcbListHead.Flink; + while (current_entry != &Fcb->ServerCcbListHead) + { + ServerCcb = CONTAINING_RECORD(current_entry, + NPFS_CCB, + CcbListEntry); + + if (ServerCcb->PipeState == FILE_PIPE_LISTENING_STATE) + { + /* found a listening server CCB */ + DPRINT("Listening server CCB found -- connecting\n"); + NpfsDereferenceFcb(Fcb); + return STATUS_SUCCESS; + } + + current_entry = current_entry->Flink; + } + + /* No listening server fcb found, so wait for one */ + + /* If a timeout specified */ + if (WaitPipe->TimeoutSpecified) + { + /* NMPWAIT_USE_DEFAULT_WAIT = 0 */ + if (WaitPipe->Timeout.QuadPart == 0) + { + TimeOut = &Fcb->TimeOut; + } + else + { + TimeOut = &WaitPipe->Timeout; + } + } + else + { + /* Wait forever */ + TimeOut = NULL; + } + NpfsDereferenceFcb(Fcb); + + Status = KeWaitForSingleObject(&Ccb->ConnectEvent, + UserRequest, + Irp->RequestorMode, + (Ccb->FileObject->Flags & FO_ALERTABLE_IO) != 0, + TimeOut); + if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC) || (Status == STATUS_ALERTED)) + Status = STATUS_CANCELLED; + + DPRINT("KeWaitForSingleObject() returned (Status %lx)\n", Status); + + return Status; +} + +NTSTATUS +NpfsWaitPipe2(PIRP Irp, + PNPFS_CCB Ccb) { PLIST_ENTRY current_entry; PNPFS_FCB Fcb; @@ -327,12 +429,16 @@ NpfsWaitPipe(PIRP Irp, PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe; LARGE_INTEGER TimeOut; NTSTATUS Status; +#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS PNPFS_VCB Vcb; UNICODE_STRING PipeName; +#endif + DPRINT("NpfsWaitPipe\n"); WaitPipe = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer; +#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS /* Fail, if the CCB does not represent the root directory */ if (Ccb->Type != CCB_DIRECTORY) return STATUS_ILLEGAL_FUNCTION; @@ -382,6 +488,15 @@ NpfsWaitPipe(PIRP Irp, } DPRINT("Fcb %p\n", Fcb); +#else + Fcb = Ccb->Fcb; + + if (Ccb->PipeState != 0) + { + DPRINT("Pipe is not in passive (waiting) state!\n"); + return STATUS_UNSUCCESSFUL; + } +#endif /* search for listening server */ current_entry = Fcb->ServerCcbListHead.Flink; @@ -395,7 +510,9 @@ NpfsWaitPipe(PIRP Irp, { /* found a listening server CCB */ DPRINT("Listening server CCB found -- connecting\n"); +#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS NpfsDereferenceFcb(Fcb); +#endif return STATUS_SUCCESS; } @@ -409,8 +526,9 @@ NpfsWaitPipe(PIRP Irp, TimeOut = WaitPipe->Timeout; else TimeOut = Fcb->TimeOut; - +#ifdef USING_PROPER_NPFS_WAIT_SEMANTICS NpfsDereferenceFcb(Fcb); +#endif /* Wait for one */ Status = KeWaitForSingleObject(&Ccb->ConnectEvent, -- 2.17.1