Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

594 lines
18 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
read.c
Abstract:
This module implements the mini redirector call down routines pertaining to
file system control(FSCTL) and Io Device Control (IOCTL) operations on file system objects.
Author:
Balan Sethu Raman [SethuR] 7-March-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <dfsfsctl.h>
//
// The local debug trace level
//
RXDT_DefineCategory(FSCTRL);
#define Dbg (DEBUG_TRACE_FSCTRL)
NTSTATUS
MRxProxyFsCtl(
IN OUT PRX_CONTEXT RxContext)
/*++
Routine Description:
This routine performs an FSCTL operation (remote) on a file across the network
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
Notes:
The FSCTL's handled by a mini rdr can be classified into one of two categories. In the
first category are those FSCTL's whose implementation are shared between RDBSS and the
mini rdr's and in the second category are those FSCTL's which are totally implemented
by the mini rdr's. To this a third category can be added, i.e., those FSCTL's which
should never be seen by the mini rdr's. The third category is solely intended as a
debugging aid.
The FSCTL's handled by a mini rdr can be classified based on functionality
--*/
{
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
RxDbgTrace(+1, Dbg, ("MRxProxyFsCtl...\n", 0));
RxDbgTrace( 0, Dbg, ("MRxProxyFsCtl = %08lx\n", FsControlCode));
switch (pLowIoContext->ParamsFor.FsCtl.MinorFunction) {
case IRP_MN_USER_FS_REQUEST:
switch (FsControlCode) {
case FSCTL_PIPE_ASSIGN_EVENT :
case FSCTL_PIPE_DISCONNECT :
case FSCTL_PIPE_LISTEN :
case FSCTL_PIPE_PEEK :
case FSCTL_PIPE_QUERY_EVENT :
case FSCTL_PIPE_TRANSCEIVE :
case FSCTL_PIPE_WAIT :
case FSCTL_PIPE_IMPERSONATE :
case FSCTL_PIPE_SET_CLIENT_PROCESS :
case FSCTL_PIPE_QUERY_CLIENT_PROCESS :
case FSCTL_MAILSLOT_PEEK :
case FSCTL_DFS_GET_REFERRALS:
case FSCTL_DFS_REPORT_INCONSISTENCY:
case FSCTL_LMR_TRANSACT :
default:
// Status = MRxProxyFsControl(RxContext);
// Temporarily stubbed out till the buffer passing strategy has been
// finalized.
Status = STATUS_NOT_IMPLEMENTED;
break;
}
break;
default :
break;
}
RxDbgTrace(-1, Dbg, ("MRxProxyFsCtl -> %08lx\n", Status ));
return Status;
}
typedef struct _PROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT_ {
PRX_CONTEXT pRxContext;
//REQ_NOTIFY_CHANGE NotifyRequest;
//PROXY_TRANSACTION_OPTIONS Options;
//PROXY_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
} PROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT, *PPROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT;
VOID
MRxProxyNotifyChangeDirectoryCompletion(
PPROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT pNotificationContext)
/*++
Routine Description:
This routine is invokde when a directory change notification operation is completed
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
Notes:
This routine will always be called. This is true even if the change directory
notification is cancelled. In such cases the memory allocated is freed without
any inteaction with the wrapped. In cases os successful directory change
notification completion the appropriate completion routine is invoked and the
RxContext modified to prevent any cancellation from proceeding further.
--*/
{
NTSTATUS Status;
PRX_CONTEXT pRxContext;
PMRXPROXY_RX_CONTEXT pMRxProxyContext;
//PPROXY_EXCHANGE pExchange = NULL;
ProxyAcquireGlobalSpinLock();
pRxContext = pNotificationContext->pRxContext;
if (pRxContext != NULL) {
// This is a case of successful completion of the change directory
// notification, i.e., the request was not cancelled. In such cases
// prevent all race conditions by modifying the RxContext under lock
// to turn back cancellation request.
pMRxProxyContext = MRxProxyGetMinirdrContext(pRxContext);
//pExchange = pMRxProxyContext->pExchange;
pMRxProxyContext->pCancelContext = NULL;
pNotificationContext->pRxContext = NULL;
}
ProxyReleaseGlobalSpinLock();
// Complete the Context if it was not previously cancelled
if (pRxContext != NULL) {
//PPROXY_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
//pResumptionContext = &(pNotificationContext->ResumptionContext);
//pRxContext->StoredStatus = pResumptionContext->FinalStatusFromServer;
Status = RxSetMinirdrCancelRoutine(pRxContext,NULL);
if (Status == STATUS_SUCCESS) {
RxLowIoCompletion(pRxContext);
}
}
#if 0
// Free the associated exchange.
if (pExchange != NULL) {
ProxyCeDereferenceAndDiscardExchange(pExchange);
}
#endif //0
// Free the notification context.
RxFreePool(pNotificationContext);
}
NTSTATUS
MRxProxyNotifyChangeDirectoryCancellation(
PRX_CONTEXT RxContext)
/*++
Routine Description:
This routine is invokde when a directory change notification operation is cancelled.
Arguments:
RxContext - the RDBSS context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
//NTSTATUS Status;
BOOLEAN ChangeDirectoryNotificationCompleted;
PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);
//PPROXY_EXCHANGE pExchange;
PPROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT pNotificationContext;
ProxyAcquireGlobalSpinLock();
pNotificationContext = (PPROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT)pMRxProxyContext->pCancelContext;
ChangeDirectoryNotificationCompleted = (pNotificationContext == NULL);
if (!ChangeDirectoryNotificationCompleted) {
// This is a case of successful cancellation of the change directory
// notification. In such cases prevent all race conditions by modifying
// the RxContext under lock to prevent successful completion
pNotificationContext->pRxContext = NULL;
//pExchange = pMRxProxyContext->pExchange;
pMRxProxyContext->pCancelContext = NULL;
}
ProxyReleaseGlobalSpinLock();
if (ChangeDirectoryNotificationCompleted) {
// The cancellation is trivial since the request has already been completed
return STATUS_SUCCESS;
}
#if 0 //can't do any of this....no exchanges.........
if (pExchange != NULL) {
UCHAR LastCommandInHeader;
PUCHAR pCommand;
BYTE CancelRequestBuffer[sizeof(PROXY_HEADER) + sizeof(REQ_NT_CANCEL)];
ULONG CancelRequestBufferSize = sizeof(CancelRequestBuffer);
// Build the Cancel request and send it across to the server.
Status = ProxyCeBuildProxyHeader(
pExchange,
CancelRequestBuffer,
CancelRequestBufferSize,
&CancelRequestBufferSize,
&LastCommandInHeader,
&pCommand);
ASSERT(LastCommandInHeader == PROXY_COM_NO_ANDX_COMMAND);
*pCommand = PROXY_COM_NT_CANCEL;
if (Status == RX_MAP_STATUS(SUCCESS)) {
PREQ_NT_CANCEL pCancelRequest = (PREQ_NT_CANCEL)(&CancelRequestBuffer[sizeof(PROXY_HEADER)]);
PMDL pCancelProxyMdl;
ProxyPutUshort(&pCancelRequest->WordCount,0);
pCancelRequest->ByteCount = 0;
CancelRequestBufferSize = sizeof(CancelRequestBuffer);
pCancelProxyMdl = RxAllocateMdl(CancelRequestBuffer,CancelRequestBufferSize);
if (pCancelProxyMdl != NULL) {
RxProbeAndLockPages(pCancelProxyMdl,KernelMode,IoModifyAccess,Status);
if (Status == STATUS_SUCCESS) {
Status = ProxyCeSend(
pExchange,
RXCE_SEND_SYNCHRONOUS,
pCancelProxyMdl,
CancelRequestBufferSize);
MmUnlockPages(pCancelProxyMdl);
}
IoFreeMdl(pCancelProxyMdl);
}
}
ProxyCeDereferenceAndDiscardExchange(pExchange);
}
#endif //0
// Complete the request.
RxContext->StoredStatus = STATUS_CANCELLED;
RxLowIoCompletion(RxContext);
return STATUS_SUCCESS;
}
NTSTATUS
MRxProxyNotifyChangeDirectory(
IN OUT PRX_CONTEXT RxContext)
/*++
Routine Description:
This routine performs a directory change notification operation
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
Notes:
THIS STUFF IS WRONG!!!!!
A directory change notification opertaion is an asychronous operation. It
consists of sending a PROXY requesting change notification whose response is
obtained when the desired change is affected on the server.
Some important points to remember are as follows .....
1) The PROXY response is not obtained till the desired change is affected on
the server. Therefore an additional MID needs to be reserved on those
connections which permit multiple MID's so that a cancel PROXY can be sent to
the server when a change notification is active.
2) The Change notification is typical of a long term ( response time
dictated by factors beyond the servers control). Another example is
the query FSCTL operation in CAIRO. For all these operations we initiate
an asychronous transact exchange.
3) The corresponding LowIo completion routine is invoked asynchronously.
4) This is an example of an operation for which the MINI RDR has to
register a context for handling cancellations initiated locally.
--*/
{
NTSTATUS Status;
RxCaptureFcb;
PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
//PPROXYCEDB_SERVER_ENTRY pServerEntry;
//PPROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT pNotificationContext;
#if 0
PBYTE pInputParamBuffer = NULL;
PBYTE pOutputParamBuffer = NULL;
PBYTE pInputDataBuffer = NULL;
PBYTE pOutputDataBuffer = NULL;
ULONG InputParamBufferLength = 0;
ULONG OutputParamBufferLength = 0;
ULONG InputDataBufferLength = 0;
ULONG OutputDataBufferLength = 0;
#endif //0
RxDbgTrace(+1, Dbg, ("MRxNotifyChangeDirectory...Entry\n", 0));
//pServerEntry = ProxyCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
//if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_PROXYS)) {
// return STATUS_NOT_SUPPORTED;
//}
#if 0
pNotificationContext =
(PPROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT)
RxAllocatePoolWithTag(
NonPagedPool,
sizeof(PROXY_NOTIFY_CHANGE_DIRECTORY_CONTEXT),
MRXPROXY_FSCTL_POOLTAG);
if (pNotificationContext != NULL) {
PREQ_NOTIFY_CHANGE pNotifyRequest;
PPROXY_TRANSACTION_OPTIONS pTransactionOptions;
PPROXY_TRANSACTION_RESUMPTION_CONTEXT pResumptionContext;
PMRX_PROXY_SRV_OPEN pProxySrvOpen;
RxCaptureFobx;
ASSERT (capFobx != NULL);
Status = MRxProxyDeferredCreate(RxContext);
if (Status==STATUS_SUCCESS) {
pProxySrvOpen = MRxProxyGetSrvOpenExtension(capFobx->pSrvOpen);
ASSERT (!FlagOn(pProxySrvOpen->Flags,PROXY_SRVOPEN_FLAG_NOT_REALLY_OPEN));
pNotificationContext->pRxContext = RxContext;
pNotifyRequest = &(pNotificationContext->NotifyRequest);
pTransactionOptions = &(pNotificationContext->Options);
pResumptionContext = &(pNotificationContext->ResumptionContext);
pNotifyRequest->CompletionFilter = pLowIoContext->ParamsFor.NotifyChangeDirectory.CompletionFilter;
pNotifyRequest->Fid = pProxySrvOpen->Fid;
pNotifyRequest->WatchTree = pLowIoContext->ParamsFor.NotifyChangeDirectory.WatchTree;
pNotifyRequest->Reserved = 0;
OutputDataBufferLength = pLowIoContext->ParamsFor.NotifyChangeDirectory.NotificationBufferLength;
pOutputDataBuffer = pLowIoContext->ParamsFor.NotifyChangeDirectory.pNotificationBuffer;
*pTransactionOptions = RxDefaultTransactionOptions;
pTransactionOptions->NtTransactFunction = NT_TRANSACT_NOTIFY_CHANGE;
pTransactionOptions->TimeoutIntervalInMilliSeconds = PROXYCE_TRANSACTION_TIMEOUT_NOT_USED;
pTransactionOptions->Flags = PROXY_XACT_FLAGS_INDEFINITE_DELAY_IN_RESPONSE;
ProxyCeInitializeAsynchronousTransactionResumptionContext(
pResumptionContext,MRxProxyNotifyChangeDirectoryCompletion,pNotificationContext);
Status = ProxyCeAsynchronousTransact(
RxContext, // the RXContext for the transaction
pTransactionOptions, // transaction options
pNotifyRequest, // the setup buffer
sizeof(REQ_NOTIFY_CHANGE), // setup buffer length
pInputParamBuffer, // Input Param Buffer
InputParamBufferLength, // Input param buffer length
pOutputParamBuffer, // Output param buffer
OutputParamBufferLength, // output param buffer length
pInputDataBuffer, // Input data buffer
InputDataBufferLength, // Input data buffer length
pOutputDataBuffer, // output data buffer
OutputDataBufferLength, // output data buffer length
pResumptionContext // the resumption context
);
if (Status == STATUS_PENDING) {
PMRXPROXY_RX_CONTEXT pMRxProxyContext;
pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext);
pMRxProxyContext->pCancelContext = pNotificationContext;
// Ensure that the appropriate cancel routine is set because this is a long term
// operation and the cancelling mechanism needs to be in place.
Status = RxSetMinirdrCancelRoutine(RxContext,MRxProxyNotifyChangeDirectoryCancellation);
if (Status == STATUS_SUCCESS) {
Status = STATUS_PENDING;
} else if (Status == STATUS_CANCELLED) {
MRxProxyNotifyChangeDirectoryCancellation(RxContext);
Status = STATUS_PENDING;
}
} else {
// On exit from this routine the request would have been completed in all
// the cases. The asynchronous case and synchronous case are folded into
// one async response by returning STATUS_PENDING.
Status = STATUS_PENDING;
}
} else {
NOTHING; //just return the status from the deferred open call
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
#endif //0
Status = STATUS_NOT_SUPPORTED;
RxDbgTrace(-1, Dbg, ("MRxProxyNotifyChangeDirectory -> %08lx\n", Status ));
return Status;
}
NTSTATUS
MRxProxyFsControl(PRX_CONTEXT RxContext)
/*++
Routine Description:
This routine handles all the FSCTL's
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
Notes:
Remoting of FSCTL's is permitted only to NT servers.
--*/
{
NTSTATUS Status;
RxCaptureFobx;
//PMRX_PROXY_SRV_OPEN pProxySrvOpen;
PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("MRxProxyFsControl...Entry FsControlCode(%lx)\n", FsControlCode));
Status = STATUS_NOT_IMPLEMENTED;
RxDbgTrace(-1, Dbg, ("MRxProxyFsControl...Exit\n"));
return Status;
}
#if DBG
NTSTATUS
MRxProxyTestForLowIoIoctl(
IN PRX_CONTEXT RxContext
)
{
NTSTATUS Status = STATUS_SUCCESS;
RxCaptureFcb;RxCaptureFobx;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
PSZ Buffer = (PSZ)(LowIoContext->ParamsFor.IoCtl.pInputBuffer);
ULONG OutputBufferLength = LowIoContext->ParamsFor.IoCtl.OutputBufferLength;
ULONG InputBufferLength = LowIoContext->ParamsFor.IoCtl.InputBufferLength;
UNICODE_STRING u;
PUNICODE_STRING FileName = &capFcb->AlreadyPrefixedName;
ULONG ReturnLength;
ReturnLength = OutputBufferLength;
if (ReturnLength > FileName->Length) {
ReturnLength = FileName->Length;
}
RxDbgTrace(0, Dbg,
("Here in MRxProxyTestForLowIoIoctl %s, obl = %08lx, rl=%08lx\n", Buffer, OutputBufferLength, ReturnLength));
//return an obvious string to make sure that darryl is copying the results out correctly
//BUGBUG need to check the lengths i.e. need outputl<=inputl; also need to check that count and buffer
// are aligned for wchar
RtlCopyMemory(Buffer,FileName->Buffer,ReturnLength);
u.Buffer = (PWCHAR)(Buffer);
u.Length = u.MaximumLength = (USHORT)ReturnLength;
RtlUpcaseUnicodeString(&u,&u,FALSE);
RxContext->InformationToReturn =
//LowIoContext->ParamsFor.IoCtl.OutputBufferLength =
ReturnLength;
return(Status);
}
#endif //if DBG
NTSTATUS
MRxProxyIoCtl(
IN OUT PRX_CONTEXT RxContext)
/*++
Routine Description:
This routine performs an IOCTL operation. Currently, no calls are remoted; in fact, the only call accepted
is for debugging.
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
ULONG IoControlCode = pLowIoContext->ParamsFor.IoCtl.IoControlCode;
RxDbgTrace(+1, Dbg, ("MRxProxyIoCtl...\n", 0));
RxDbgTrace( 0, Dbg, ("MRxProxyIoCtl = %08lx\n", IoControlCode));
switch (IoControlCode) {
#if DBG
case IOCTL_LMMR_TESTLOWIO:
Status = MRxProxyTestForLowIoIoctl(RxContext);
break;
#endif //if DBG
default:
break;
}
RxDbgTrace(-1, Dbg, ("MRxProxyIoCtl -> %08lx\n", Status ));
return Status;
}