|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
FsContrl.c
Abstract:
This module implements the File System Control routine for NPFS called by the dispatch driver.
Author:
Gary Kimura [GaryKi] 21-Aug-1990
Revision History:
--*/
#include "NpProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (NPFS_BUG_CHECK_FSCTRL)
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_FSCONTRL)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, NpAssignEvent)
#pragma alloc_text(PAGE, NpCommonFileSystemControl)
#pragma alloc_text(PAGE, NpCompleteTransceiveIrp)
#pragma alloc_text(PAGE, NpDisconnect)
#pragma alloc_text(PAGE, NpFsdFileSystemControl)
#pragma alloc_text(PAGE, NpImpersonate)
#pragma alloc_text(PAGE, NpInternalRead)
#pragma alloc_text(PAGE, NpInternalTransceive)
#pragma alloc_text(PAGE, NpInternalWrite)
#pragma alloc_text(PAGE, NpListen)
#pragma alloc_text(PAGE, NpPeek)
#pragma alloc_text(PAGE, NpQueryClientProcess)
#pragma alloc_text(PAGE, NpQueryEvent)
#pragma alloc_text(PAGE, NpSetClientProcess)
#pragma alloc_text(PAGE, NpTransceive)
#pragma alloc_text(PAGE, NpWaitForNamedPipe)
#endif
NTSTATUS NpFsdFileSystemControl ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine implements the FSD part of the NtFsControlFile API calls.
Arguments
NpfsDeviceObject - Supplies the device object to use.
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The Fsd status for the Irp
--*/
{ NTSTATUS Status;
PAGED_CODE();
DebugTrace(+1, Dbg, "NpFsdFileSystemControl\n", 0);
//
// Call the common FsControl routine.
//
FsRtlEnterFileSystem();
Status = NpCommonFileSystemControl( NpfsDeviceObject, Irp ); FsRtlExitFileSystem();
if (Status != STATUS_PENDING) { NpCompleteRequest (Irp, Status); }
//
// And return to our caller
//
DebugTrace(-1, Dbg, "NpFsdFileSystemControl -> %08lx\n", Status );
return Status; }
//
// Internal Support Routine
//
NTSTATUS NpCommonFileSystemControl ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the common code for handling/dispatching an fsctl function.
Arguments:
NpfsDeviceObject - Supplies the named pipe device object
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The return status for the operation
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp; BOOLEAN ReadOverflowOperation; LIST_ENTRY DeferredList;
PAGED_CODE();
//
// Reference our input parameters to make things easier
//
IrpSp = IoGetCurrentIrpStackLocation (Irp);
InitializeListHead (&DeferredList);
DebugTrace(+1, Dbg, "NpCommonFileSystemControl\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", IrpSp->Parameters.FileSystemControl.OutputBufferLength); DebugTrace( 0, Dbg, "InputBufferLength = %08lx\n", IrpSp->Parameters.FileSystemControl.InputBufferLength); DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", IrpSp->Parameters.FileSystemControl.FsControlCode);
//
// Case on the type of function we're trying to do. In each case
// we'll call a local work routine to do the actual work.
//
ReadOverflowOperation = FALSE;
switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
case FSCTL_PIPE_ASSIGN_EVENT:
NpAcquireExclusiveVcb (); Status = NpAssignEvent (NpfsDeviceObject, Irp); break;
case FSCTL_PIPE_DISCONNECT:
NpAcquireExclusiveVcb (); Status = NpDisconnect (NpfsDeviceObject, Irp, &DeferredList); break;
case FSCTL_PIPE_LISTEN:
NpAcquireSharedVcb (); Status = NpListen (NpfsDeviceObject, Irp, &DeferredList); break;
case FSCTL_PIPE_PEEK:
NpAcquireExclusiveVcb (); Status = NpPeek (NpfsDeviceObject, Irp, &DeferredList); break;
case FSCTL_PIPE_QUERY_EVENT:
NpAcquireExclusiveVcb (); Status = NpQueryEvent (NpfsDeviceObject, Irp); break;
case FSCTL_PIPE_TRANSCEIVE:
NpAcquireSharedVcb (); Status = NpTransceive (NpfsDeviceObject, Irp, &DeferredList); break;
case FSCTL_PIPE_WAIT:
NpAcquireExclusiveVcb (); Status = NpWaitForNamedPipe (NpfsDeviceObject, Irp); break;
case FSCTL_PIPE_IMPERSONATE:
NpAcquireExclusiveVcb (); Status = NpImpersonate (NpfsDeviceObject, Irp); break;
case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
ReadOverflowOperation = TRUE;
case FSCTL_PIPE_INTERNAL_READ:
NpAcquireSharedVcb (); Status = NpInternalRead (NpfsDeviceObject, Irp, ReadOverflowOperation, &DeferredList); break;
case FSCTL_PIPE_INTERNAL_WRITE:
NpAcquireSharedVcb (); Status = NpInternalWrite (NpfsDeviceObject, Irp, &DeferredList); break;
case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
NpAcquireSharedVcb (); Status = NpInternalTransceive (NpfsDeviceObject, Irp, &DeferredList); break;
case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
NpAcquireSharedVcb (); Status = NpQueryClientProcess (NpfsDeviceObject, Irp); break;
case FSCTL_PIPE_SET_CLIENT_PROCESS:
NpAcquireExclusiveVcb (); Status = NpSetClientProcess (NpfsDeviceObject, Irp); break;
default:
return STATUS_NOT_SUPPORTED; // No lock acquired
}
NpReleaseVcb ();
//
// Complete any deferred IRPs now we have dropped the last lock
//
NpCompleteDeferredIrps (&DeferredList);
//
// And return to our caller
//
DebugTrace(-1, Dbg, "NpCommonFileSystemControl -> %08lx\n", Status);
return Status; }
//
// Local support routine
//
NTSTATUS NpAssignEvent ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the assign event control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the Irp specifying the function
Return Value:
NTSTATUS - An appropriate return status
--*/
{ PIO_STACK_LOCATION IrpSp;
ULONG InputBufferLength; ULONG FsControlCode;
PCCB Ccb; PNONPAGED_CCB NonpagedCcb; NAMED_PIPE_END NamedPipeEnd;
PFILE_PIPE_ASSIGN_EVENT_BUFFER EventBuffer; NTSTATUS status;
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpAssignEvent...\n", 0);
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
//
// Decode the file object to figure out who we are. If the result
// is not a ccb then the pipe has been disconnected.
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd ) != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
return STATUS_PIPE_DISCONNECTED; }
NonpagedCcb = Ccb->NonpagedCcb;
//
// Reference the system buffer as an assign event buffer and make
// sure it's large enough
//
EventBuffer = Irp->AssociatedIrp.SystemBuffer;
if (InputBufferLength < sizeof(FILE_PIPE_ASSIGN_EVENT_BUFFER)) {
DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
return STATUS_INVALID_PARAMETER; }
//
// First thing we do is delete the old event if there is one
// for this end of the pipe
//
NpDeleteEventTableEntry( &NpVcb->EventTable, NonpagedCcb->EventTableEntry[ NamedPipeEnd ] );
NonpagedCcb->EventTableEntry[ NamedPipeEnd ] = NULL;
//
// Now if the new event handle is not null then we'll add the new
// event to the event table
//
status = STATUS_SUCCESS; if (EventBuffer->EventHandle != NULL) {
status = NpAddEventTableEntry( &NpVcb->EventTable, Ccb, NamedPipeEnd, EventBuffer->EventHandle, EventBuffer->KeyValue, PsGetCurrentProcess(), Irp->RequestorMode, &NonpagedCcb->EventTableEntry[ NamedPipeEnd ] ); }
DebugTrace(-1, Dbg, "NpAssignEvent -> STATUS_SUCCESS\n", 0); return status; }
//
// Local Support Routine
//
NTSTATUS NpDisconnect ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the disconnect control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
DeferredList - List of IRPs to complete after we drop the locks
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp;
ULONG FsControlCode;
PCCB Ccb; NAMED_PIPE_END NamedPipeEnd;
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpDisconnect...\n", 0);
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
//
// Decode the file object to figure out who we are. If the result
// is not a ccb then the pipe has been disconnected.
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd ) != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
return STATUS_PIPE_DISCONNECTED; }
//
// Make sure that this is only the server that is doing this
// action.
//
if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
DebugTrace(0, Dbg, "Not the server end\n", 0);
return STATUS_ILLEGAL_FUNCTION; }
NpAcquireExclusiveCcb(Ccb);
//
// Now call the state support routine to set the ccb to
// a disconnected state and remove the client's cached security
// context.
//
Status = NpSetDisconnectedPipeState( Ccb, DeferredList );
NpUninitializeSecurity( Ccb );
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpDisconnect -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpListen ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the listen control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
DeferredList - List of IRPs to complete once we drop the locks
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp;
ULONG FsControlCode;
PCCB Ccb; NAMED_PIPE_END NamedPipeEnd;
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpListen...\n", 0);
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
//
// Decode the file object to figure out who we are. If the result
// is not a ccb then the pipe has been disconnected.
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd ) != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
DebugTrace(-1, Dbg, "NpListen -> STATUS_ILLEGAL_FUNCTION\n", 0 ); return STATUS_ILLEGAL_FUNCTION; }
//
// Make sure that this is only the server that is doing this
// action.
//
if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
DebugTrace(0, Dbg, "Not the server end\n", 0);
DebugTrace(-1, Dbg, "NpListen -> STATUS_ILLEGAL_FUNCTION\n", 0 ); return STATUS_ILLEGAL_FUNCTION; }
NpAcquireExclusiveCcb(Ccb);
//
// Now call the state support routine to set the ccb to
// a listening state. This routine will complete the Irp
// for us.
//
Status = NpSetListeningPipeState( Ccb, Irp, DeferredList );
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpListen -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpPeek ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the peek control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
DeferredList - List of IRPS to be completed after we drop the locks
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp;
ULONG OutputBufferLength; ULONG FsControlCode;
NODE_TYPE_CODE NodeTypeCode; PCCB Ccb; PNONPAGED_CCB NonpagedCcb; NAMED_PIPE_END NamedPipeEnd;
PFILE_PIPE_PEEK_BUFFER PeekBuffer;
PDATA_QUEUE ReadQueue; READ_MODE ReadMode;
ULONG LengthWritten;
PUCHAR ReadBuffer; ULONG ReadLength; ULONG ReadRemaining; PDATA_ENTRY DataEntry;
PAGED_CODE();
//
// Get the current Irp stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpPeek...\n", 0);
//
// Extract the important fields from the IrpSp
//
OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", OutputBufferLength); DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode);
//
// Decode the file object to figure out who we are. The results
// have a disconnected pipe if we get back an undefined ntc
//
if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "FileObject has been disconnected\n", 0);
DebugTrace(-1, Dbg, "NpPeek -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED; }
//
// Now make sure the node type code is for a ccb otherwise it is an
// invalid parameter
//
if (NodeTypeCode != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "FileObject is not for a ccb\n", 0);
DebugTrace(-1, Dbg, "NpPeek -> STATUS_INVALID_PARAMETER\n", 0 ); return STATUS_INVALID_PARAMETER; }
NonpagedCcb = Ccb->NonpagedCcb;
//
// Reference the system buffer as a peek buffer and make sure it's
// large enough
//
if (OutputBufferLength < (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])) {
DebugTrace(0, Dbg, "Output buffer is too small\n", 0);
DebugTrace(-1, Dbg, "NpPeek -> STATUS_INVALID_PARAMETER\n", 0 ); return STATUS_INVALID_PARAMETER; }
PeekBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// Now the data queue that we read from is based on the named pipe
// end. The server reads from the inbound queue and the client reads
// from the outbound queue
//
switch (NamedPipeEnd) {
case FILE_PIPE_SERVER_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ]; //ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
break;
case FILE_PIPE_CLIENT_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ]; //ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
break;
default:
NpBugCheck( NamedPipeEnd, 0, 0 ); }
//
// Our read mode is really based upon the pipe type and not the set
// read mode for the pipe end.
//
if (Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) {
ReadMode = FILE_PIPE_MESSAGE_MODE;
} else {
ReadMode = FILE_PIPE_BYTE_STREAM_MODE; }
DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue); DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
//
// If the state of the pipe is not in the connected or closing
// state then it is an invalid pipe state
//
if ((Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) && (Ccb->NamedPipeState != FILE_PIPE_CLOSING_STATE)) {
DebugTrace(0, Dbg, "pipe not connected or closing\n", 0);
return STATUS_INVALID_PIPE_STATE; }
//
// If the state of the pipe is closing and the queue does
// not contain any writers then we return eof
//
if ((Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) && (!NpIsDataQueueWriters( ReadQueue ))) {
DebugTrace(0, Dbg, "pipe closing and is empty\n", 0);
return STATUS_PIPE_BROKEN; }
//
// Zero out the standard header part of the peek buffer and
// set the length written to the amount we've just zeroed out
//
RtlZeroMemory( PeekBuffer, FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]) ); LengthWritten = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
//
// Set the named pipe state
//
PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
//
// There is only data available if the read queue contains
// write entries otherwise the rest of record is all zero.
//
if (NpIsDataQueueWriters( ReadQueue )) {
//
// Now find the first real entry in the read queue. The
// first entry actually better be a real one.
//
DataEntry = NpGetNextDataQueueEntry( ReadQueue, NULL );
ASSERT( (DataEntry->DataEntryType == Buffered) || (DataEntry->DataEntryType == Unbuffered) );
//
// Indicate how many bytes are available to read
//
PeekBuffer->ReadDataAvailable = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset;
//
// The number of messages and message length is only filled
// in for a message mode pipe
//
if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
PeekBuffer->NumberOfMessages = ReadQueue->EntriesInQueue; PeekBuffer->MessageLength = DataEntry->DataSize - ReadQueue->NextByteOffset; }
//
// Now we are ready to copy over the data from the read queue
// into the peek buffer. First establish how much room we
// have in the peek buffer and who much is remaining.
//
ReadBuffer = &PeekBuffer->Data[0]; ReadLength = OutputBufferLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]); ReadRemaining = ReadLength;
DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer); DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
//
// Now read the data queue.
//
if ( ReadLength != 0 ) { IO_STATUS_BLOCK Iosb;
Iosb = NpReadDataQueue( ReadQueue, TRUE, FALSE, ReadBuffer, ReadLength, ReadMode, Ccb, DeferredList );
Status = Iosb.Status; LengthWritten += (ULONG)Iosb.Information;
} else {
if ( PeekBuffer->ReadDataAvailable == 0) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_BUFFER_OVERFLOW; } }
} else {
Status = STATUS_SUCCESS; }
//
// Complete the request. The amount of information copied
// is stored in length written
//
Irp->IoStatus.Information = LengthWritten;
DebugTrace(-1, Dbg, "NpPeek -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpQueryEvent ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the query event control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the Irp specifying the function
Return Value:
NTSTATUS - An appropriate return status
--*/
{ PIO_STACK_LOCATION IrpSp;
ULONG InputBufferLength; ULONG OutputBufferLength; ULONG FsControlCode;
PCCB Ccb; NAMED_PIPE_END NamedPipeEnd;
HANDLE EventHandle; PFILE_PIPE_EVENT_BUFFER EventArray; PFILE_PIPE_EVENT_BUFFER EventBuffer; ULONG EventArrayMaximumCount; ULONG EventCount;
PEPROCESS Process;
PEVENT_TABLE_ENTRY Ete; PDATA_QUEUE ReadQueue; PDATA_QUEUE WriteQueue;
PVOID RestartKey;
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpQueryEvent...\n", 0);
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
//
// Decode the file object to figure out who we are. If the result
// is not a Vcb then its an invalid parameter
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd ) != NPFS_NTC_VCB) {
DebugTrace(0, Dbg, "FileObject is not the named pipe driver\n", 0);
return STATUS_INVALID_PARAMETER; }
//
// Reference the system buffer as a handle and make sure it's large
// enough
//
if (InputBufferLength < sizeof(HANDLE)) {
DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
return STATUS_INVALID_PARAMETER; } EventHandle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
//
// Reference the system buffer as an output event buffer, and compute
// how many event buffer records we can put in the buffer.
//
EventArray = Irp->AssociatedIrp.SystemBuffer; EventArrayMaximumCount = OutputBufferLength / sizeof(FILE_PIPE_EVENT_BUFFER); EventCount = 0;
//
// Get our current process pointer that we'll need for our search
//
Process = PsGetCurrentProcess();
//
// Now enumerate the event table entries in the event table
//
RestartKey = NULL; for (Ete = NpGetNextEventTableEntry( &NpVcb->EventTable, &RestartKey); Ete != NULL; Ete = NpGetNextEventTableEntry( &NpVcb->EventTable, &RestartKey)) {
//
// Check if the event table entry matches the event handle
// and the process
//
if ((Ete->EventHandle == EventHandle) && (Ete->Process == Process)) {
//
// Now based on the named pipe end we treat the inbound/
// outbound as a read/write queue.
//
NpAcquireExclusiveCcb(Ete->Ccb);
switch (Ete->NamedPipeEnd) {
case FILE_PIPE_CLIENT_END:
ReadQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_OUTBOUND ]; WriteQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_INBOUND ];
break;
case FILE_PIPE_SERVER_END:
ReadQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_INBOUND ]; WriteQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
break;
default:
NpBugCheck( Ete->NamedPipeEnd, 0, 0 ); }
//
// Now if there is any data in the read queue to be read
// we fill in the buffer
//
if (NpIsDataQueueWriters(ReadQueue)) {
//
// First make sure there is enough room in the
// EventBuffer to hold another entry
//
if (EventCount >= EventArrayMaximumCount) {
DebugTrace(0, Dbg, "The event buffer is full\n", 0);
NpReleaseCcb(Ete->Ccb); break; }
//
// Reference the event buffer and increment the
// counter
//
EventBuffer = &EventArray[EventCount]; EventCount += 1;
//
// Fill in the event buffer entry
//
EventBuffer->NamedPipeState = Ete->Ccb->NamedPipeState; EventBuffer->EntryType = FILE_PIPE_READ_DATA; EventBuffer->ByteCount = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset; EventBuffer->KeyValue = Ete->KeyValue; EventBuffer->NumberRequests = ReadQueue->EntriesInQueue; }
//
// We'll always fill in a write space buffer. The amount
// will either be bytes of write space available or
// the quota of write space that we can use.
//
//
// First make sure there is enough room in the
// EventBuffer to hold another entry
//
if (EventCount >= EventArrayMaximumCount) {
DebugTrace(0, Dbg, "The event buffer is full\n", 0);
NpReleaseCcb(Ete->Ccb); break; }
//
// Reference the event buffer and increment the
// counter
//
EventBuffer = &EventArray[EventCount]; EventCount += 1;
//
// Fill in the event buffer entry
//
EventBuffer->NamedPipeState = Ete->Ccb->NamedPipeState; EventBuffer->EntryType = FILE_PIPE_WRITE_SPACE; EventBuffer->KeyValue = Ete->KeyValue;
//
// Now either we put in the write space available or
// we put in the quota available
//
if (NpIsDataQueueReaders(WriteQueue)) {
EventBuffer->ByteCount = WriteQueue->BytesInQueue - WriteQueue->NextByteOffset; EventBuffer->NumberRequests = WriteQueue->EntriesInQueue;
} else {
EventBuffer->ByteCount = WriteQueue->Quota - WriteQueue->QuotaUsed; EventBuffer->NumberRequests = 0; }
NpReleaseCcb(Ete->Ccb); } }
//
// Set the information field to be the number of bytes of output
// data we've fill into the system buffer
//
Irp->IoStatus.Information = EventCount * sizeof(FILE_PIPE_EVENT_BUFFER);
DebugTrace(-1, Dbg, "NpQueryEvent -> STATUS_SUCCESS\n", 0); return STATUS_SUCCESS; }
//
// Local Support Routine
//
NTSTATUS NpTransceive ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the transceive named pipe control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
DeferredList - List of IRPs to complete after we drop locks
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ static IO_STATUS_BLOCK Iosb; NTSTATUS Status;
PIO_STACK_LOCATION IrpSp; PETHREAD UserThread;
PUCHAR WriteBuffer; ULONG WriteLength;
PUCHAR ReadBuffer; ULONG ReadLength;
NODE_TYPE_CODE NodeTypeCode; PCCB Ccb; PNONPAGED_CCB NonpagedCcb; NAMED_PIPE_END NamedPipeEnd;
PDATA_QUEUE ReadQueue; PDATA_QUEUE WriteQueue; PEVENT_TABLE_ENTRY Event; READ_MODE ReadMode;
NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
ULONG WriteRemaining; PIRP WriteIrp;
//
// The following variable is used during abnormal unwind
//
PVOID UnwindStorage = NULL;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpTransceive\n", 0); DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; ReadBuffer = Irp->UserBuffer;
//
// Now if the requestor mode is user mode we need to probe the buffers
// We do now need to have an exception handler here because our top
// level caller already has one that will complete the Irp with
// the appropriate status if we access violate.
//
if (Irp->RequestorMode != KernelMode) {
try {
ProbeForRead( WriteBuffer, WriteLength, sizeof(UCHAR) ); ProbeForWrite( ReadBuffer, ReadLength, sizeof(UCHAR) );
} except(EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode (); } }
//
// Get the Ccb and figure out who we are, and make sure we're not
// disconnected
//
if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
DebugTrace(-1, Dbg, "NpTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED; }
//
// Now we only will allow transceive operations on the pipe and not a
// directory or the device
//
if (NodeTypeCode != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
DebugTrace(-1, Dbg, "NpTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED; }
NonpagedCcb = Ccb->NonpagedCcb;
NpAcquireExclusiveCcb(Ccb); WriteIrp = NULL;
try {
//
// Check that the pipe is in the connected state
//
if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
DebugTrace(0, Dbg, "Pipe not connected\n", 0);
try_return( Status = STATUS_INVALID_PIPE_STATE ); }
//
// Figure out the read/write queue, read mode, and event based
// on the end of the named pipe doing the transceive.
//
switch (NamedPipeEnd) {
case FILE_PIPE_SERVER_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ]; WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ]; ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
break;
case FILE_PIPE_CLIENT_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ]; WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ]; ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
break;
default:
NpBugCheck( NamedPipeEnd, 0, 0 ); }
//
// We only allow a transceive on a message mode, full duplex pipe.
//
NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) || (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
try_return( Status = STATUS_INVALID_PIPE_STATE ); }
//
// Check that the read queue is empty.
//
if (!NpIsDataQueueEmpty( ReadQueue )) {
DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
try_return( Status = STATUS_PIPE_BUSY ); }
//
// Do the transceive write operation. We first try and push the data
// from the write buffer into any waiting readers in the write queue
// and if that succeeds then we can go on and do the read operation
// otherwise we need to make a copy of irp and to enqueue as
// a data entry into the write queue.
//
// Now we'll call our common write data queue routine to
// transfer data out of our write buffer into the data queue.
// If the result of the call is FALSE then we still have some
// write data to put into the write queue.
//
UserThread = Irp->Tail.Overlay.Thread; Status = NpWriteDataQueue( WriteQueue, ReadMode, WriteBuffer, WriteLength, Ccb->Fcb->Specific.Fcb.NamedPipeType, &WriteRemaining, Ccb, NamedPipeEnd, UserThread, DeferredList );
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
PIO_STACK_LOCATION WriteIrpSp;
ASSERT( !NpIsDataQueueReaders( WriteQueue ));
DebugTrace(0, Dbg, "Add write to data queue\n", 0);
//
// We need to do some more write processing. So to handle
// this case we'll allocate a new irp and set its system
// buffer to be the remaining part of the write buffer
//
if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, TRUE )) == NULL) {
try_return (Status = STATUS_INSUFFICIENT_RESOURCES); }
IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
if (WriteRemaining > 0) {
WriteIrp->AssociatedIrp.SystemBuffer = NpAllocatePagedPoolWithQuota( WriteRemaining, 'wFpN' ); if (WriteIrp->AssociatedIrp.SystemBuffer == NULL) { IoFreeIrp (WriteIrp); try_return (Status = STATUS_INSUFFICIENT_RESOURCES); }
//
// Safely do the copy
//
try {
RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer, &WriteBuffer[ WriteLength - WriteRemaining ], WriteRemaining );
} except(EXCEPTION_EXECUTE_HANDLER) { NpFreePool (WriteIrp->AssociatedIrp.SystemBuffer); IoFreeIrp (WriteIrp); try_return (Status = GetExceptionCode ()); }
} else {
WriteIrp->AssociatedIrp.SystemBuffer = NULL; }
//
// Set the current stack location, and set in the amount we are
// try to write.
//
WriteIrp->CurrentLocation -= 1; WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp; WriteIrp->Tail.Overlay.Thread = UserThread; WriteIrp->IoStatus.Information = WriteRemaining;
WriteIrpSp->Parameters.Write.Length = WriteRemaining; WriteIrpSp->MajorFunction = IRP_MJ_WRITE;
//
// Set it up to do buffered I/O and deallocate the buffer
// on completion.
if (WriteRemaining > 0) {
WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; }
WriteIrp->UserIosb = &Iosb;
//
// Add this write request to the write queue
//
Status = NpAddDataQueueEntry( NamedPipeEnd, Ccb, WriteQueue, WriteEntries, Unbuffered, WriteRemaining, WriteIrp, NULL, 0);
if (Status != STATUS_PENDING) { NpDeferredCompleteRequest (WriteIrp, Status, DeferredList); }
}
if (!NT_SUCCESS (Status)) { try_return (NOTHING); }
//
// And because we've done something we need to signal the
// other ends event
//
NpSignalEventTableEntry( Event );
//
// Do the transceive read operation. This is just like a
// buffered read.
//
// Now we know that the read queue is empty so we'll enqueue this
// Irp to the read queue and return status pending, also mark the
// irp pending
//
ASSERT( NpIsDataQueueEmpty( ReadQueue ));
Status = NpAddDataQueueEntry( NamedPipeEnd, Ccb, ReadQueue, ReadEntries, Buffered, ReadLength, Irp, NULL, 0 ); if (!NT_SUCCESS (Status)) { try_return (NOTHING); }
//
// And because we've done something we need to signal the
// other ends event
//
NpSignalEventTableEntry( Event );
try_exit: NOTHING; } finally { NpReleaseCcb(Ccb); }
DebugTrace(-1, Dbg, "NpTransceive -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpWaitForNamedPipe ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the wait for named pipe control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp;
ULONG InputBufferLength; ULONG FsControlCode;
PFCB Fcb; PCCB Ccb;
PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer; UNICODE_STRING Name; PVOID LocalBuffer;
PLIST_ENTRY Links;
BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
UNICODE_STRING RemainingPart; BOOLEAN Translated;
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpWaitForNamedPipe...\n", 0);
//
// Extract the important fields from the IrpSp
//
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
Name.Buffer = NULL; LocalBuffer = NULL;
try {
//
// Decode the file object to figure out who we are. If the result
// is an error if the we weren't given a Vcb.
//
{ PCCB Ccb; NAMED_PIPE_END NamedPipeEnd;
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd ) != NPFS_NTC_ROOT_DCB) {
DebugTrace(0, Dbg, "File Object is not for the named pipe root directory\n", 0);
try_return( Status = STATUS_ILLEGAL_FUNCTION ); } }
//
// Reference the system buffer as a wait for buffer and make
// sure it's large enough
//
if (InputBufferLength < sizeof(FILE_PIPE_WAIT_FOR_BUFFER)) {
DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
try_return( Status = STATUS_INVALID_PARAMETER ); }
WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// Check for an invalid buffer. The Name Length cannot be greater than
// MAXUSHORT minus the backslash otherwise it will overflow the buffer.
// We don't need to check for less than 0 because it is unsigned.
//
if ((WaitBuffer->NameLength > (MAXUSHORT - 2)) || (FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + WaitBuffer->NameLength > InputBufferLength)) {
DebugTrace(0, Dbg, "System buffer size or name length is too small\n", 0);
try_return( Status = STATUS_INVALID_PARAMETER ); }
//
// Set up the local variable Name to be the name we're looking
// for
//
Name.Length = (USHORT)(WaitBuffer->NameLength + 2); Name.Buffer = LocalBuffer = NpAllocatePagedPool( Name.Length, 'WFpN' ); if (LocalBuffer == NULL) { try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); }
Name.Buffer[0] = L'\\';
RtlCopyMemory( &Name.Buffer[1], &WaitBuffer->Name[0], WaitBuffer->NameLength );
//
// If the name is an alias, translate it
//
Status = NpTranslateAlias( &Name );
if ( !NT_SUCCESS(Status) ) {
try_return( NOTHING ); }
//
// Now check to see if we can find a named pipe with the right
// name
//
Fcb = NpFindPrefix( &Name, CaseInsensitive, &RemainingPart );
//
// If the Fcb is null then we can't wait for it, Also if the
// Fcb is not an Fcb then we also have nothing to wait for
//
if (NodeType(Fcb) != NPFS_NTC_FCB) {
DebugTrace(0, Dbg, "Bad nonexistent named pipe name", 0);
try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND ); }
//
// If translated then Name.Buffer would point to the translated buffer
//
Translated = (Name.Buffer != LocalBuffer);
//
// Now we need to search to see if we find a ccb already in the
// listening state
// First try and find a ccb that is in the listening state
// If we exit the loop with ccb null then we haven't found
// one
//
Ccb = NULL; for (Links = Fcb->Specific.Fcb.CcbQueue.Flink; Links != &Fcb->Specific.Fcb.CcbQueue; Links = Links->Flink) {
Ccb = CONTAINING_RECORD( Links, CCB, CcbLinks );
if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
break; }
Ccb = NULL; }
//
// Check if we found one
//
if (Ccb != NULL) {
DebugTrace(0, Dbg, "Found a ccb in listening state\n", 0);
try_return( Status = STATUS_SUCCESS ); }
//
// We weren't able to find one so we need to add a new waiter
//
Status = NpAddWaiter( &NpVcb->WaitQueue, Fcb->Specific.Fcb.DefaultTimeOut, Irp, Translated ? &Name : NULL);
try_exit: NOTHING; } finally {
if (LocalBuffer != NULL) { NpFreePool( LocalBuffer ); } }
DebugTrace(-1, Dbg, "NpWaitForNamedPipe -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpImpersonate ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the impersonate of the named pipe
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status; PIO_STACK_LOCATION IrpSp;
PCCB Ccb; NAMED_PIPE_END NamedPipeEnd;
UNREFERENCED_PARAMETER( NpfsDeviceObject );
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpImpersonate...\n", 0);
//
// Decode the file object to figure out who we are. If the result
// is an error if the we weren't given a Vcb.
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd ) != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "File Object is not a named pipe\n", 0);
DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 ); return STATUS_ILLEGAL_FUNCTION; }
//
// Make sure that we are the server end and not the client end
//
if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
DebugTrace(0, Dbg, "Not the server end\n", 0);
DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 ); return STATUS_ILLEGAL_FUNCTION; }
//
// set up the impersonation
//
Status = NpImpersonateClientContext( Ccb );
DebugTrace(-1, Dbg, "NpImpersonate -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpInternalRead ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN BOOLEAN ReadOverflowOperation, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the unbuffered read named pipe control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
ReadOverflowOperation - Used to indicate if the read being processed is a read overflow operation.
DeferredList - List of IRP's to be completed later after we drop the locks
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status;
PIO_STACK_LOCATION IrpSp;
NODE_TYPE_CODE NodeTypeCode; PCCB Ccb; PNONPAGED_CCB NonpagedCcb; NAMED_PIPE_END NamedPipeEnd;
NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
PIRP ReadIrp; PUCHAR ReadBuffer; ULONG ReadLength; ULONG ReadRemaining; READ_MODE ReadMode; COMPLETION_MODE CompletionMode; PDATA_QUEUE ReadQueue; PEVENT_TABLE_ENTRY Event;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpInternalRead\n", 0); DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
//
// Get the Ccb and figure out who we are, and make sure we're not
// disconnected
//
if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED; }
//
// Now we only will allow Read operations on the pipe and not a directory
// or the device
//
if (NodeTypeCode != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 ); return STATUS_INVALID_PARAMETER; }
NonpagedCcb = Ccb->NonpagedCcb;
NpAcquireExclusiveCcb(Ccb);
//
// Check if the pipe is not in the connected state.
//
switch (Ccb->NamedPipeState) {
case FILE_PIPE_DISCONNECTED_STATE:
DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED;
case FILE_PIPE_LISTENING_STATE:
DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_LISTENING\n", 0 ); return STATUS_PIPE_LISTENING;
case FILE_PIPE_CONNECTED_STATE: case FILE_PIPE_CLOSING_STATE:
break;
default:
DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState); NpBugCheck( Ccb->NamedPipeState, 0, 0 ); }
//
// We only allow a read by the server on a non outbound only pipe
// and by the client on a non inbound only pipe
//
NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
if (((NamedPipeEnd == FILE_PIPE_SERVER_END) && (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))
||
((NamedPipeEnd == FILE_PIPE_CLIENT_END) && (NamedPipeConfiguration == FILE_PIPE_INBOUND))) {
DebugTrace(0, Dbg, "Trying to read to the wrong pipe configuration\n", 0);
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 ); return STATUS_INVALID_PARAMETER; }
//
// Reference our input parameters to make things easier, and
// initialize our main variables that describe the Read command
//
ReadIrp = Irp; ReadBuffer = Irp->AssociatedIrp.SystemBuffer; ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; ReadRemaining = ReadLength; ReadMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].ReadMode; CompletionMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].CompletionMode;
if (ReadOverflowOperation == TRUE && ReadMode != FILE_PIPE_MESSAGE_MODE) { NpReleaseCcb(Ccb); return STATUS_INVALID_READ_MODE; }
//
// Now the data queue that we read from into and the event that we signal
// are based on the named pipe end. The server read from the inbound
// queue and signals the client event. The client does just the
// opposite.
//
switch (NamedPipeEnd) {
case FILE_PIPE_SERVER_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
break;
case FILE_PIPE_CLIENT_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
break;
default:
NpBugCheck( NamedPipeEnd, 0, 0 ); }
DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer); DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength); DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode); DebugTrace(0, Dbg, "CompletionMode = %08lx\n", CompletionMode); DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue); DebugTrace(0, Dbg, "Event = %08lx\n", Event);
//
// if the read queue does not contain any write entries
// then we either need to enqueue this operation or
// fail immediately
//
if (!NpIsDataQueueWriters( ReadQueue )) {
//
// Check if the other end of the pipe is closing, and if
// so then we complete it with end of file.
// Otherwise check to see if we should enqueue the irp
// or complete the operation and tell the user the pipe is empty.
//
if (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
DebugTrace(0, Dbg, "Complete the irp with eof\n", 0);
Status = STATUS_PIPE_BROKEN;
} else if (CompletionMode == FILE_PIPE_QUEUE_OPERATION) {
DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
Status = NpAddDataQueueEntry( NamedPipeEnd, Ccb, ReadQueue, ReadEntries, Unbuffered, ReadLength, ReadIrp, NULL, 0 );
} else {
DebugTrace(0, Dbg, "Complete the irp with pipe empty\n", 0);
Status = STATUS_PIPE_EMPTY; }
} else {
//
// otherwise there we have a read irp against a read queue
// that contains one or more write entries.
//
ReadIrp->IoStatus = NpReadDataQueue( ReadQueue, FALSE, ReadOverflowOperation, ReadBuffer, ReadLength, ReadMode, Ccb, DeferredList );
Status = ReadIrp->IoStatus.Status;
//
// Now set the remaining byte count in the allocation size of
// the Irp.
//
ReadIrp->Overlay.AllocationSize.QuadPart = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset;
//
// Finish up the read irp.
//
}
//
// And because we've done something we need to signal the
// other ends event
//
NpSignalEventTableEntry( Event );
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpInternalRead -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpInternalWrite ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the unbuffered write named pipe control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ NTSTATUS Status;
PIO_STACK_LOCATION IrpSp; PETHREAD UserThread;
NODE_TYPE_CODE NodeTypeCode; PCCB Ccb; PNONPAGED_CCB NonpagedCcb; NAMED_PIPE_END NamedPipeEnd;
NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
PIRP WriteIrp; PUCHAR WriteBuffer; ULONG WriteLength; ULONG WriteRemaining; PDATA_QUEUE WriteQueue;
PEVENT_TABLE_ENTRY Event; READ_MODE ReadMode;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpInternalWrite\n", 0); DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
//
// This is a FSCTL path being used as a write. Make sure we can set the .Information field to the number
// of bytes written.
//
NpConvertFsctlToWrite (Irp);
//
// Get the Ccb and figure out who we are, and make sure we're not
// disconnected
//
if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED; }
//
// Now we only will allow write operations on the pipe and not a directory
// or the device
//
if (NodeTypeCode != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0); return STATUS_PIPE_DISCONNECTED; }
NonpagedCcb = Ccb->NonpagedCcb;
NpAcquireExclusiveCcb(Ccb);
//
// We only allow a write by the server on a non inbound only pipe
// and by the client on a non outbound only pipe
//
NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
if (((NamedPipeEnd == FILE_PIPE_SERVER_END) && (NamedPipeConfiguration == FILE_PIPE_INBOUND))
||
((NamedPipeEnd == FILE_PIPE_CLIENT_END) && (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
DebugTrace(0, Dbg, "Trying to write to the wrong pipe configuration\n", 0);
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0); return STATUS_PIPE_DISCONNECTED; }
//
// Reference our input parameters to make things easier, and
// initialize our main variables that describe the write command
//
WriteIrp = Irp; WriteBuffer = Irp->AssociatedIrp.SystemBuffer; WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
//
// Set up the amount of data we will have written by the time this
// irp gets completed
//
WriteIrp->IoStatus.Information = WriteLength;
//
// Now the data queue that we write into and the event that we signal
// are based on the named pipe end. The server writes to the outbound
// queue and signals the client event. The client does just the
// opposite. We also need to figure out the read mode for the opposite
// end of the pipe.
//
switch (NamedPipeEnd) {
case FILE_PIPE_SERVER_END:
WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ]; ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
break;
case FILE_PIPE_CLIENT_END:
WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ]; ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
break;
default:
NpBugCheck( NamedPipeEnd, 0, 0 ); }
//
// Check if the pipe is not in the connected state.
//
switch (Ccb->NamedPipeState) {
case FILE_PIPE_DISCONNECTED_STATE:
DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
NpReleaseCcb(Ccb); return STATUS_PIPE_DISCONNECTED;
case FILE_PIPE_LISTENING_STATE:
DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
NpReleaseCcb(Ccb); return STATUS_PIPE_LISTENING;
case FILE_PIPE_CONNECTED_STATE:
break;
case FILE_PIPE_CLOSING_STATE:
DebugTrace(0, Dbg, "Pipe in closing state\n", 0);
NpReleaseCcb(Ccb); return STATUS_PIPE_CLOSING;
default:
DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState); NpBugCheck( Ccb->NamedPipeState, 0, 0 ); }
//
// Check if this is a message type pipe and the operation type is complete
// operation, If so then we also check that the queued reads is enough to
// complete the message otherwise we need to abort the write irp immediately.
//
if ((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) && (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION)) {
//
// If the pipe contains readers and amount to read is less than the write
// length then we cannot do it the write.
// Or if pipe does not contain reads then we also cannot do the write.
//
if ((NpIsDataQueueReaders( WriteQueue ) && (WriteQueue->BytesInQueue < WriteLength))
||
(!NpIsDataQueueReaders( WriteQueue ))) {
DebugTrace(0, Dbg, "Cannot complete the message without blocking\n", 0);
NpReleaseCcb(Ccb); Irp->IoStatus.Information = 0; return STATUS_SUCCESS; } }
//
// Now we'll call our common write data queue routine to
// transfer data out of our write buffer into the data queue.
// If the result of the call is FALSE then we still have some
// write data to put into the write queue.
//
UserThread = Irp->Tail.Overlay.Thread; Status = NpWriteDataQueue( WriteQueue, ReadMode, WriteBuffer, WriteLength, Ccb->Fcb->Specific.Fcb.NamedPipeType, &WriteRemaining, Ccb, NamedPipeEnd, UserThread, DeferredList );
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
ASSERT( !NpIsDataQueueReaders( WriteQueue ));
//
// Check if the operation is not to block and if so then we
// will complete the operation now with what we're written, if what is
// left will not fit in the quota for the file
//
if (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
DebugTrace(0, Dbg, "Complete the byte stream write immediately\n", 0);
Irp->IoStatus.Information = WriteLength - WriteRemaining;
Status = STATUS_SUCCESS;
} else {
DebugTrace(0, Dbg, "Add write to data queue\n", 0);
//
// Add this write request to the write queue
//
Status = NpAddDataQueueEntry( NamedPipeEnd, Ccb, WriteQueue, WriteEntries, Unbuffered, WriteLength, Irp, NULL, WriteLength - WriteRemaining);
}
} else {
DebugTrace(0, Dbg, "Complete the Write Irp\n", 0);
//
// The write irp is finished so we can complete it now
//
}
//
// And because we've done something we need to signal the
// other ends event
//
NpSignalEventTableEntry( Event );
NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpInternalWrite -> %08lx\n", Status); return Status; }
//
// Local Support Routine
//
NTSTATUS NpInternalTransceive ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp, IN PLIST_ENTRY DeferredList )
/*++
Routine Description:
This routine does the internal (i.e., unbuffered) transceive named pipe control function
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
DeferredList - List of IRP's to be completed once we drop our locks.
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ static IO_STATUS_BLOCK Iosb; NTSTATUS Status;
PIO_STACK_LOCATION IrpSp; PETHREAD UserThread;
PUCHAR WriteBuffer; ULONG WriteLength;
PUCHAR ReadBuffer; ULONG ReadLength;
NODE_TYPE_CODE NodeTypeCode; PCCB Ccb; PNONPAGED_CCB NonpagedCcb; NAMED_PIPE_END NamedPipeEnd;
PDATA_QUEUE ReadQueue; PDATA_QUEUE WriteQueue; PEVENT_TABLE_ENTRY Event; READ_MODE ReadMode;
NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
ULONG WriteRemaining;
PIRP WriteIrp;
//
// The following variable is used for abnormal unwind
//
PVOID UnwindStorage = NULL;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpInternalTransceive\n", 0); DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// Get the Ccb and figure out who we are, and make sure we're not
// disconnected
//
if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, &NamedPipeEnd )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 ); return STATUS_PIPE_DISCONNECTED; }
//
// Now we only will allow transceive operations on the pipe and not a
// directory or the device
//
if (NodeTypeCode != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_INVALID_PARAMETER\n", 0 ); return STATUS_INVALID_PARAMETER; }
NonpagedCcb = Ccb->NonpagedCcb;
WriteIrp = NULL; NpAcquireExclusiveCcb(Ccb);
try {
//
// Check that the pipe is in the connected state
//
if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
DebugTrace(0, Dbg, "Pipe not connected\n", 0);
try_return( Status = STATUS_INVALID_PIPE_STATE ); }
//
// Figure out the read/write queue, read mode, and event based
// on the end of the named pipe doing the transceive.
//
switch (NamedPipeEnd) {
case FILE_PIPE_SERVER_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ]; WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ]; ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
break;
case FILE_PIPE_CLIENT_END:
ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ]; WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ]; ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
break;
default:
NpBugCheck( NamedPipeEnd, 0, 0 ); }
//
// We only allow a transceive on a message mode, full duplex pipe.
//
NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) || (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
try_return( Status = STATUS_INVALID_READ_MODE ); }
//
// Check that the read queue is empty.
//
if (!NpIsDataQueueEmpty( ReadQueue )) {
DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
try_return( Status = STATUS_PIPE_BUSY ); }
//
// Do the transceive write operation. We first try and push the data
// from the write buffer into any waiting readers in the write queue
// and if that succeeds then we can go on and do the read operation
// otherwise we need to make a copy of irp and to enqueue as
// a data entry into the write queue.
//
// Now we'll call our common write data queue routine to
// transfer data out of our write buffer into the data queue.
// If the result of the call is FALSE then we still have some
// write data to put into the write queue.
//
UserThread = Irp->Tail.Overlay.Thread; Status = NpWriteDataQueue( WriteQueue, ReadMode, WriteBuffer, WriteLength, Ccb->Fcb->Specific.Fcb.NamedPipeType, &WriteRemaining, Ccb, NamedPipeEnd, UserThread, DeferredList ); if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
PIO_STACK_LOCATION WriteIrpSp;
ASSERT( !NpIsDataQueueReaders( WriteQueue ));
DebugTrace(0, Dbg, "Add write to data queue\n", 0);
//
// We need to do some more write processing. So to handle
// this case we'll allocate a new irp and set its system
// buffer to be the remaining part of the write buffer
//
if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, TRUE )) == NULL) {
try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); }
IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
if (WriteRemaining > 0) {
WriteIrp->AssociatedIrp.SystemBuffer = NpAllocatePagedPoolWithQuota( WriteRemaining, 'wFpN' ); if (WriteIrp->AssociatedIrp.SystemBuffer == NULL) { IoFreeIrp (WriteIrp); try_return (Status = STATUS_INSUFFICIENT_RESOURCES); } //
// Safely do the copy
//
try {
RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer, &WriteBuffer[ WriteLength - WriteRemaining ], WriteRemaining );
WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
} except(EXCEPTION_EXECUTE_HANDLER) { NpFreePool (WriteIrp->AssociatedIrp.SystemBuffer); IoFreeIrp (WriteIrp); try_return (Status = GetExceptionCode ()); }
} else {
WriteIrp->AssociatedIrp.SystemBuffer = NULL; }
//
// Set the current stack location
//
WriteIrp->CurrentLocation -= 1; WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp; WriteIrp->Tail.Overlay.Thread = UserThread; WriteIrpSp->MajorFunction = IRP_MJ_WRITE; WriteIrp->UserIosb = &Iosb;
//
// Add this write request to the write queue
//
Status = NpAddDataQueueEntry( NamedPipeEnd, Ccb, WriteQueue, WriteEntries, Unbuffered, WriteRemaining, WriteIrp, NULL, 0 ); if (Status != STATUS_PENDING) { NpDeferredCompleteRequest (WriteIrp, Status, DeferredList); } } if (!NT_SUCCESS (Status)) { try_return (NOTHING) } //
// And because we've done something we need to signal the
// other ends event
//
NpSignalEventTableEntry( Event );
//
// Do the transceive read operation. This is just like an
// unbuffered read.
//
// Now we know that the read queue is empty so we'll enqueue this
// Irp to the read queue and return status pending, also mark the
// irp pending
//
ASSERT( NpIsDataQueueEmpty( ReadQueue ));
Status = NpAddDataQueueEntry( NamedPipeEnd, Ccb, ReadQueue, ReadEntries, Unbuffered, ReadLength, Irp, NULL, 0 ); if (!NT_SUCCESS (Status)) { try_return (Status); }
//
// And because we've done something we need to signal the
// other ends event
//
NpSignalEventTableEntry( Event );
try_exit: NOTHING; } finally {
NpReleaseCcb(Ccb); }
DebugTrace(-1, Dbg, "NpInternalTransceive -> %08lx\n", Status); return Status; }
//
// Internal support routine
//
NTSTATUS NpQueryClientProcess ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the query client process named pipe control function
The output buffer may be either a FILE_PIPE_CLIENT_PROCESS_BUFFER or a FILE_PIPE_CLIENT_PROCESS_BUFFER_EX.
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ PIO_STACK_LOCATION IrpSp;
ULONG OutputBufferLength;
PCCB Ccb;
PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcessBuffer; PCLIENT_INFO ClientInfo; CLIENT_INFO NullInfo = {0};
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpQueryClientProcess\n", 0);
OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
//
// Decode the file object to figure out who we are.
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
return STATUS_PIPE_DISCONNECTED; }
//
// Make sure the output buffer is large enough
//
if (OutputBufferLength < sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER)) {
DebugTrace(0, Dbg, "Output System buffer size is too small\n", 0);
return STATUS_INVALID_PARAMETER; }
NpAcquireExclusiveCcb(Ccb);
//
// Copy over the client process ID
//
ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer; ClientProcessBuffer->ClientProcess = Ccb->ClientProcess;
ClientInfo = Ccb->ClientInfo; if (ClientInfo == NULL) { ClientInfo = &NullInfo; } ClientProcessBuffer->ClientSession = ClientInfo->ClientSession;
//
// Return extended client information if so requested
// Set the information field to the size of the client process
// buffer
//
if (OutputBufferLength >= sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX)) {
ClientProcessBuffer->ClientComputerNameLength = ClientInfo->ClientComputerNameLength;
RtlCopyMemory( ClientProcessBuffer->ClientComputerBuffer, ClientInfo->ClientComputerBuffer, ClientInfo->ClientComputerNameLength ); ClientProcessBuffer->ClientComputerBuffer[ ClientProcessBuffer->ClientComputerNameLength / sizeof(WCHAR)] = L'\0';
Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX);
} else {
Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER);
} NpReleaseCcb(Ccb);
DebugTrace(-1, Dbg, "NpQueryClientProcess -> STATUS_SUCCESS\n", 0); return STATUS_SUCCESS; }
//
// Internal support routine
//
NTSTATUS NpSetClientProcess ( IN PNPFS_DEVICE_OBJECT NpfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the set client process named pipe control function
Note that we expect a FILE_PIPE_CLIENT_PROCESS_BUFFER_EX structure to be passed in to us.
Arguments:
NpfsDeviceObject - Supplies our device object
Irp - Supplies the being processed
Return Value:
NTSTATUS - An apprropriate return status
--*/
{ PIO_STACK_LOCATION IrpSp; PCLIENT_INFO ClientInfo; ULONG InputBufferLength;
PCCB Ccb;
PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcessBuffer;
PAGED_CODE();
//
// Get the current stack location
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NpSetClientProcess\n", 0);
//
// Only allow kernel callers for this API as RPC relies on this info being solid.
//
if (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL) { return STATUS_ACCESS_DENIED; }
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
//
// Decode the file object to figure out who we are.
//
if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
return STATUS_PIPE_DISCONNECTED; }
//
// Make sure the input buffer is large enough
//
if (InputBufferLength != sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX)) {
DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
return STATUS_INVALID_PARAMETER; }
ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// Make verify input length is valid
//
if (ClientProcessBuffer->ClientComputerNameLength > FILE_PIPE_COMPUTER_NAME_LENGTH * sizeof (WCHAR)) {
DebugTrace(0, Dbg, "Computer Name length is too large\n", 0);
return STATUS_INVALID_PARAMETER; }
ClientInfo = NpAllocatePagedPoolWithQuota (FIELD_OFFSET (CLIENT_INFO, ClientComputerBuffer) + ClientProcessBuffer->ClientComputerNameLength, 'iFpN');
if (ClientInfo == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } if (Ccb->ClientInfo != NULL) { NpFreePool (Ccb->ClientInfo); }
Ccb->ClientInfo = ClientInfo; //
// Copy over the client process ID
//
ClientInfo->ClientSession = ClientProcessBuffer->ClientSession; Ccb->ClientProcess = ClientProcessBuffer->ClientProcess;
ClientInfo->ClientComputerNameLength = ClientProcessBuffer->ClientComputerNameLength; RtlCopyMemory( ClientInfo->ClientComputerBuffer, ClientProcessBuffer->ClientComputerBuffer, ClientProcessBuffer->ClientComputerNameLength );
DebugTrace(-1, Dbg, "NpSetClientProcess -> STATUS_SUCCESS\n", 0); return STATUS_SUCCESS; }
//
// Internal support routine
//
NTSTATUS NpCompleteTransceiveIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
/*++
Routine Description:
This is a local i/o completion routine used to complete the special Irps allocated for transcieve. This routine simply deallocate the irp and return status more processing
Arguments:
DeviceObject - Supplies the device object
Irp - Supplies the Irp to complete
Context - Supplies the context for the Irp
Return Value:
NTSTATUS - STATUS_MORE_PROCESSING_REQUIRED
--*/
{ UNREFERENCED_PARAMETER( DeviceObject ); UNREFERENCED_PARAMETER( Context );
PAGED_CODE();
if (Irp->AssociatedIrp.SystemBuffer != NULL) {
NpFreePool( Irp->AssociatedIrp.SystemBuffer ); }
IoFreeIrp( Irp );
return STATUS_MORE_PROCESSING_REQUIRED; }
|