[NPFS/KERNEL32]

* Back out r59915 for a moment so we can use Patchbot.

svn path=/trunk/; revision=59934
This commit is contained in:
Amine Khaldi 2013-09-01 10:16:29 +00:00
parent e28e6935a6
commit 23c4a2e25f
3 changed files with 310 additions and 45 deletions

View file

@ -14,6 +14,8 @@
#include <debug.h>
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

View file

@ -13,6 +13,8 @@
#define NDEBUG
#include <debug.h>
//#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.
*/
CurrentEntry = Fcb->ServerCcbListHead.Flink;
while (CurrentEntry != &Fcb->ServerCcbListHead)
{
Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry);
if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
{
ServerCcb = Ccb;
break;
}
CurrentEntry = CurrentEntry->Flink;
}
/*
* No one is listening to me?! I'm so lonely... :(
* 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)
{
/* Not found, bail out with error for FILE_OPEN requests. */
DPRINT("No listening server CCB found!\n");
if (ClientCcb->Data)
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)
{
ExFreePoolWithTag(ClientCcb->Data, TAG_NPFS_CCB_DATA);
Ccb = CONTAINING_RECORD(CurrentEntry, NPFS_CCB, CcbListEntry);
if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
{
ServerCcb = Ccb;
break;
}
CurrentEntry = CurrentEntry->Flink;
}
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;
/*
* 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)
{
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;
}
}
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.

View file

@ -15,6 +15,8 @@
#define NDEBUG
#include <debug.h>
//#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,