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.
1939 lines
61 KiB
1939 lines
61 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cancel.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines relating to the cancel logic in the
|
|
DAV MiniRedir.
|
|
|
|
Author:
|
|
|
|
Rohan Kumar [RohanK] 10-April-2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "ntverp.h"
|
|
#include "netevent.h"
|
|
#include "nvisible.h"
|
|
#include "webdav.h"
|
|
#include "ntddmup.h"
|
|
#include "rxdata.h"
|
|
#include "fsctlbuf.h"
|
|
|
|
//
|
|
// The timeout values for various operations used by the MiniRedir. If an
|
|
// operation is not completed within the timeout value specified for it, is
|
|
// cancelled. The user can set the value to 0xffffffff to disable the
|
|
// timeout/cancel logic. In other words, if the timeout value is 0xffffffff,
|
|
// the requests will never timeout.
|
|
//
|
|
ULONG CreateRequestTimeoutValueInSec;
|
|
ULONG CreateVNetRootRequestTimeoutValueInSec;
|
|
ULONG QueryDirectoryRequestTimeoutValueInSec;
|
|
ULONG CloseRequestTimeoutValueInSec;
|
|
ULONG CreateSrvCallRequestTimeoutValueInSec;
|
|
ULONG FinalizeSrvCallRequestTimeoutValueInSec;
|
|
ULONG FinalizeFobxRequestTimeoutValueInSec;
|
|
ULONG FinalizeVNetRootRequestTimeoutValueInSec;
|
|
ULONG ReNameRequestTimeoutValueInSec;
|
|
ULONG SetFileInfoRequestTimeoutValueInSec;
|
|
ULONG QueryFileInfoRequestTimeoutValueInSec;
|
|
ULONG QueryVolumeInfoRequestTimeoutValueInSec;
|
|
ULONG LockRefreshRequestTimeoutValueInSec;
|
|
|
|
//
|
|
// The timer thread wakes up every "TimerThreadSleepTimeInSec" and cancels all
|
|
// the requests which haven't completed in their specified timeout value. This
|
|
// value is set to the min of the timeout values of all the requests mentioned
|
|
// above.
|
|
//
|
|
ULONG TimerThreadSleepTimeInSec;
|
|
|
|
//
|
|
// The timer object used by the timer thread that cancels the requests which
|
|
// have not completed in a specified time.
|
|
//
|
|
KTIMER DavTimerObject;
|
|
|
|
//
|
|
// This is used to indicate the timer thread to shutdown. When the system is
|
|
// being shutdown this is set to TRUE. MRxDAVTimerThreadLock is the resource
|
|
// used to gain access to this variable.
|
|
//
|
|
BOOL TimerThreadShutDown;
|
|
ERESOURCE MRxDAVTimerThreadLock;
|
|
|
|
//
|
|
// The handle of the timer thread that is created using PsCreateSystemThread
|
|
// is stored this global.
|
|
//
|
|
HANDLE TimerThreadHandle;
|
|
|
|
//
|
|
// This event is signalled by the timer thread right before its going to
|
|
// terminate itself.
|
|
//
|
|
KEVENT TimerThreadEvent;
|
|
|
|
//
|
|
// If QueueLockRefreshWorkItem is TRUE, the TimerThread (which cancels all the
|
|
// AsyncEngineContexts that haven't completed in a specified time) queues a
|
|
// WorkItem to refresh the locks. After the WorkItem has been queued the value
|
|
// of QueueLockRefreshWorkItem is set to FALSE. Once the worker thread is
|
|
// done refreshing all the locks, it resets this value to TRUE. We have a
|
|
// corresponding lock QueueLockRefreshWorkItemLock to synchronize access to
|
|
// QueueLockRefreshWorkItem.
|
|
//
|
|
BOOL QueueLockRefreshWorkItem;
|
|
ERESOURCE QueueLockRefreshWorkItemLock;
|
|
|
|
//
|
|
// The WorkQueueItem used in the MRxDAVContextTimerThread function to refresh
|
|
// the LOCKs taken by this client.
|
|
//
|
|
RX_WORK_QUEUE_ITEM LockRefreshWorkQueueItem;
|
|
|
|
NTSTATUS
|
|
MRxDAVCancelTheContext(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVCompleteTheCancelledRequest(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleGeneralCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleQueryDirCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCloseSrvOpenCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleSetFileInfoCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCreateCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCreateSrvCallCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleSrvCallFinalizeCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCreateVNetRootCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleFinalizeVNetRootCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCleanupFobxCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleRenameCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleQueryFileInfoCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleLockRefreshCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
);
|
|
|
|
VOID
|
|
MRxDAVRefreshTheServerLocks(
|
|
PVOID DummyContext
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVRefreshTheServerLocksContinuation(
|
|
UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
|
|
);
|
|
|
|
NTSTATUS
|
|
MRxDAVFormatUserModeRefreshTheServerLockRequest(
|
|
IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
|
|
IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
|
|
IN ULONG WorkItemLength,
|
|
OUT PULONG_PTR ReturnedLength
|
|
);
|
|
|
|
BOOL
|
|
MRxDAVPrecompleteUserModeRefreshTheServerLockRequest(
|
|
UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
|
|
PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
|
|
ULONG WorkItemLength,
|
|
BOOL OperationCancelled
|
|
);
|
|
|
|
//
|
|
// Implementation of functions begins here.
|
|
//
|
|
|
|
NTSTATUS
|
|
MRxDAVCancelRoutine(
|
|
PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initiates the cancellation of an I/O request.
|
|
|
|
Arguments:
|
|
|
|
RxContext - The RX_CONTEXT instance which needs to be cancelled.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PLIST_ENTRY listEntry = NULL;
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
|
|
BOOL lockAcquired = FALSE, contextFound = FALSE;
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCancelRoutine. RxContext = %08lx\n",
|
|
PsGetCurrentThreadId(), RxContext));
|
|
|
|
ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
|
|
lockAcquired = TRUE;
|
|
|
|
listEntry = UMRxAsyncEngineContextList.Flink;
|
|
|
|
while ( listEntry != &(UMRxAsyncEngineContextList) ) {
|
|
|
|
//
|
|
// Get the pointer to the UMRX_ASYNCENGINE_CONTEXT structure.
|
|
//
|
|
AsyncEngineContext = CONTAINING_RECORD(listEntry,
|
|
UMRX_ASYNCENGINE_CONTEXT,
|
|
ActiveContextsListEntry);
|
|
|
|
listEntry = listEntry->Flink;
|
|
|
|
//
|
|
// Check to see if this entry is for the RxContext in question.
|
|
//
|
|
if (AsyncEngineContext->RxContext == RxContext) {
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCancelRoutine: RxContext: %08lx FOUND\n",
|
|
PsGetCurrentThreadId(), RxContext));
|
|
contextFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (!contextFound) {
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCancelTheContext: RxContext: %08lx NOT FOUND\n",
|
|
PsGetCurrentThreadId(), RxContext));
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
NtStatus = MRxDAVCancelTheContext(AsyncEngineContext, TRUE);
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
//
|
|
// If we acquired the UMRxAsyncEngineContextListLock, then we need to
|
|
// release it now.
|
|
//
|
|
if (lockAcquired) {
|
|
ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
|
|
lockAcquired = FALSE;
|
|
}
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCancelTheContext: Returning NtStatus = %08lx\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
VOID
|
|
MRxDAVContextTimerThread(
|
|
PVOID DummyContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This timer thread is created with this routine. The thread waits on a timer
|
|
object which gets signalled TimerThreadSleepTimeInSec after it has been
|
|
inserted into the timer queue.
|
|
|
|
Arguments:
|
|
|
|
DummyContext - A dummy context that is supplied.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
LONGLONG DueTimeInterval;
|
|
LONG CopyTheRequestTimeValue;
|
|
BOOLEAN setTimer = FALSE, lockAcquired = FALSE;
|
|
|
|
CopyTheRequestTimeValue = TimerThreadSleepTimeInSec;
|
|
|
|
do {
|
|
|
|
//
|
|
// If TimerThreadShutDown is set to TRUE, it means that the system is
|
|
// being shutdown. The job of this thread is done. We check here after
|
|
// we have gone through the context list and before we restart the wait.
|
|
// We also check this below as soon as the DavTimerObject is signalled.
|
|
//
|
|
ExAcquireResourceExclusiveLite(&(MRxDAVTimerThreadLock), TRUE);
|
|
lockAcquired = TRUE;
|
|
if (TimerThreadShutDown) {
|
|
break;
|
|
}
|
|
ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
|
|
lockAcquired = FALSE;
|
|
|
|
//
|
|
// We set the DueTimeInterval to be -ve TimerThreadSleepTimeInSec in 100
|
|
// nano seconds. This is because this tells KeSetTimerEx that the
|
|
// expiration time is relative to the current system time.
|
|
//
|
|
DueTimeInterval = ( -CopyTheRequestTimeValue * 1000 * 1000 * 10 );
|
|
|
|
//
|
|
// Call KeSetTimerEx to insert the TimerObject in the system's timer
|
|
// queue. Also, the return value should be FALSE since this timer
|
|
// should not exist in the system queue.
|
|
//
|
|
setTimer = KeSetTimerEx(&(DavTimerObject), *(PLARGE_INTEGER)&(DueTimeInterval), 0, NULL);
|
|
ASSERT(setTimer == FALSE);
|
|
|
|
//
|
|
// Wait for the timer object to be signalled. This call should only
|
|
// return if the wait has been satisfied, which implies that the return
|
|
// value is STATUS_SUCCESS.
|
|
//
|
|
NtStatus = KeWaitForSingleObject(&(DavTimerObject),
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
ASSERT(NtStatus == STATUS_SUCCESS);
|
|
|
|
//
|
|
// If TimerThreadShutDown is set to TRUE, it means that the system is
|
|
// being shutdown. The job of this thread is done. We check as soon as
|
|
// the DavTimerObject is signalled. We also check this above as soon
|
|
// as we complete cycling through the context list.
|
|
//
|
|
ExAcquireResourceExclusiveLite(&(MRxDAVTimerThreadLock), TRUE);
|
|
lockAcquired = TRUE;
|
|
if (TimerThreadShutDown) {
|
|
break;
|
|
}
|
|
ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
|
|
lockAcquired = FALSE;
|
|
|
|
//
|
|
// Now call MRxDAVTimeOutTheContexts which cycles through all the
|
|
// currently active contexts and cancels the ones that have been hanging
|
|
// around for more than their timeout values.
|
|
//
|
|
MRxDAVTimeOutTheContexts(FALSE);
|
|
|
|
//
|
|
// Now call MRxDAVCleanUpTheLockConflictList to delete all the expired
|
|
// entries from the global LockConflictEntryList.
|
|
//
|
|
MRxDAVCleanUpTheLockConflictList(FALSE);
|
|
|
|
//
|
|
// We now post a workitem to a system worker thread. This calls the
|
|
// function MRxDAVRefreshTheServerLocks which refreshes all the
|
|
// currently active LOCKs. This is done if QueueLockRefreshWorkItem
|
|
// is TRUE. After posting the workitem, its set to FALSE. Once the
|
|
// workitem is dequeued and the locks are refreshed, its reset to
|
|
// TRUE by the worker thread.
|
|
//
|
|
ExAcquireResourceExclusiveLite(&(QueueLockRefreshWorkItemLock), TRUE);
|
|
if (QueueLockRefreshWorkItem) {
|
|
NtStatus = RxPostToWorkerThread((PRDBSS_DEVICE_OBJECT)MRxDAVDeviceObject,
|
|
CriticalWorkQueue,
|
|
&(LockRefreshWorkQueueItem),
|
|
MRxDAVRefreshTheServerLocks,
|
|
NULL);
|
|
ASSERT(NtStatus == STATUS_SUCCESS);
|
|
QueueLockRefreshWorkItem = FALSE;
|
|
}
|
|
ExReleaseResourceLite(&(QueueLockRefreshWorkItemLock));
|
|
|
|
} while (TRUE);
|
|
|
|
//
|
|
// If the lock is still acquired, we need to release it.
|
|
//
|
|
if (lockAcquired) {
|
|
ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
|
|
lockAcquired = FALSE;
|
|
}
|
|
|
|
//
|
|
// Set the timer thread event signalling that the timer thread is done
|
|
// with the MRxDAVTimerThreadLock and that it can be deleted.
|
|
//
|
|
KeSetEvent(&(TimerThreadEvent), 0, FALSE);
|
|
|
|
//
|
|
// Close the thread handle to remove the reference on the object. We need
|
|
// to do this before we call PsTerminateSystemThread.
|
|
//
|
|
ZwClose(TimerThreadHandle);
|
|
|
|
//
|
|
// Terminate this thread since we are going to shutdown now.
|
|
//
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
MRxDAVTimeOutTheContexts(
|
|
BOOL WindDownAllContexts
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the thread that wakes up every "X" minutes to see
|
|
if some AsyncEngineContext has been hanging around in the active contexts
|
|
list for more than "X" minutes. If it finds some such context, it just cancels
|
|
the operation. The value "X" is read from the registry and is stored in the
|
|
global variable MRxDAVRequestTimeoutValueInSec at driver init time. This value
|
|
defaults to 10 min. In other words, if an operation has not completed in "X"
|
|
minutes, it is cancelled. The user can set this value to 0xffffffff to turn
|
|
off the timeout.
|
|
|
|
It can also be called by the thread that is trying to complete all the
|
|
requests and stop the MiniRedir. This happens when the WebClient service
|
|
is being stopped.
|
|
|
|
Arguments:
|
|
|
|
WindDownAllContexts - If this is set to TRUE, then all the contexts are
|
|
cancelled no matter when they were added to the list.
|
|
This is set to FALSE by the timer thread and to TRUE
|
|
by the thread that is stopping the MiniRedir.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PLIST_ENTRY listEntry = NULL;
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
|
|
PWEBDAV_CONTEXT DavContext = NULL;
|
|
BOOL lockAcquired = FALSE;
|
|
LARGE_INTEGER CurrentSystemTickCount, TickCountDifference;
|
|
LARGE_INTEGER RequestTimeoutValueInTickCount;
|
|
ULONG RequestTimeoutValueInSec = 0;
|
|
|
|
ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
|
|
lockAcquired = TRUE;
|
|
|
|
listEntry = UMRxAsyncEngineContextList.Flink;
|
|
|
|
while ( listEntry != &(UMRxAsyncEngineContextList) ) {
|
|
|
|
//
|
|
// Get the pointer to the UMRX_ASYNCENGINE_CONTEXT structure.
|
|
//
|
|
AsyncEngineContext = CONTAINING_RECORD(listEntry,
|
|
UMRX_ASYNCENGINE_CONTEXT,
|
|
ActiveContextsListEntry);
|
|
|
|
listEntry = listEntry->Flink;
|
|
|
|
DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
|
|
|
|
if (!WindDownAllContexts) {
|
|
|
|
switch (DavContext->EntryPoint) {
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATE:
|
|
RequestTimeoutValueInSec = CreateRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CLEANUPFOBX:
|
|
RequestTimeoutValueInSec = FinalizeFobxRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL:
|
|
RequestTimeoutValueInSec = CreateSrvCallRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT:
|
|
RequestTimeoutValueInSec = CreateVNetRootRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_FINALIZESRVCALL:
|
|
RequestTimeoutValueInSec = FinalizeSrvCallRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_FINALIZEVNETROOT:
|
|
RequestTimeoutValueInSec = FinalizeVNetRootRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CLOSESRVOPEN:
|
|
RequestTimeoutValueInSec = CloseRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_RENAME:
|
|
RequestTimeoutValueInSec = ReNameRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_QUERYDIR:
|
|
RequestTimeoutValueInSec = QueryDirectoryRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_SETFILEINFORMATION:
|
|
RequestTimeoutValueInSec = SetFileInfoRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_QUERYFILEINFORMATION:
|
|
RequestTimeoutValueInSec = QueryFileInfoRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_QUERYVOLUMEINFORMATION:
|
|
RequestTimeoutValueInSec = QueryVolumeInfoRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_REFRESHTHELOCK:
|
|
RequestTimeoutValueInSec = LockRefreshRequestTimeoutValueInSec;
|
|
break;
|
|
|
|
default:
|
|
DbgPrint("MRxDAVTimeOutTheContexts: EntryPoint = %d\n", DavContext->EntryPoint);
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
//
|
|
// Calculate the timeout value in TickCount (100 nano seconds) using
|
|
// the timeout value in seconds) which we got from above. Step1 below
|
|
// calculates the number of ticks that happen in one second. Step2
|
|
// below calculates the number of ticks in RequestTimeoutValueInSec.
|
|
//
|
|
RequestTimeoutValueInTickCount.QuadPart = ( (1000 * 1000 * 10) / KeQueryTimeIncrement() );
|
|
RequestTimeoutValueInTickCount.QuadPart *= RequestTimeoutValueInSec;
|
|
|
|
KeQueryTickCount( &(CurrentSystemTickCount) );
|
|
|
|
//
|
|
// Get the time elapsed (in system tick counts) since the time this
|
|
// AsyncEngineContext was created.
|
|
//
|
|
TickCountDifference.QuadPart = (CurrentSystemTickCount.QuadPart - AsyncEngineContext->CreationTimeInTickCount.QuadPart);
|
|
|
|
//
|
|
// If the amount of time that has elapsed since this context was added
|
|
// to the list is greater than the timeout value, then cancel the
|
|
// request.
|
|
//
|
|
if (TickCountDifference.QuadPart > RequestTimeoutValueInTickCount.QuadPart) {
|
|
NtStatus = MRxDAVCancelTheContext(AsyncEngineContext, FALSE);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we were asked to wind down all the contexts then we cancel
|
|
// every request no matter when it was inserted into the active
|
|
// context list.
|
|
//
|
|
NtStatus = MRxDAVCancelTheContext(AsyncEngineContext, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lockAcquired) {
|
|
ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
|
|
lockAcquired = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVCancelTheContext(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the cancellation of an I/O request. The caller of this
|
|
routine needs to acquire the global UMRxAsyncEngineContextListLock before
|
|
the call is made.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The UMRX_ASYNCENGINE_CONTEXT instance which needs to be
|
|
cancelled.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PWEBDAV_CONTEXT DavContext = NULL;
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCancelTheContext. AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
|
|
|
|
//
|
|
// We do not cancel read and wrtie operations.
|
|
//
|
|
switch (DavContext->EntryPoint) {
|
|
case DAV_MINIRDR_ENTRY_FROM_READ:
|
|
case DAV_MINIRDR_ENTRY_FROM_WRITE:
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
//
|
|
// We shouldn't be getting cancel I/O calls for which the MiniRedir callouts
|
|
// which cannot be cancelled by the user. These can however be cancelled
|
|
// by the timeout thread.
|
|
//
|
|
if (UserInitiatedCancel) {
|
|
switch (DavContext->EntryPoint) {
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL:
|
|
case DAV_MINIRDR_ENTRY_FROM_FINALIZESRVCALL:
|
|
case DAV_MINIRDR_ENTRY_FROM_CLEANUPFOBX:
|
|
case DAV_MINIRDR_ENTRY_FROM_FINALIZEVNETROOT:
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT:
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATE:
|
|
DbgPrint("MRxDAVCancelTheContext: Invalid EntryPoint = %d\n", DavContext->EntryPoint);
|
|
ASSERT(FALSE);
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
}
|
|
|
|
switch (AsyncEngineContext->AsyncEngineContextState) {
|
|
|
|
case UMRxAsyncEngineContextAllocated:
|
|
case UMRxAsyncEngineContextInUserMode:
|
|
AsyncEngineContext->AsyncEngineContextState = UMRxAsyncEngineContextCancelled;
|
|
break;
|
|
|
|
default:
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCancelTheContext: NOT Being Cancelled. AsyncEngineContextState: %d\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext->AsyncEngineContextState));
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
}
|
|
|
|
NtStatus = MRxDAVCompleteTheCancelledRequest(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVCompleteTheCancelledRequest(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion if the request that has been cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context of the operation that is being
|
|
cancelled.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PWEBDAV_CONTEXT DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVCompleteTheCancelledRequest. AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
switch (DavContext->EntryPoint) {
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL:
|
|
NtStatus = MRxDAVHandleCreateSrvCallCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT:
|
|
NtStatus = MRxDAVHandleCreateVNetRootCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_FINALIZESRVCALL:
|
|
NtStatus = MRxDAVHandleSrvCallFinalizeCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_FINALIZEVNETROOT:
|
|
NtStatus = MRxDAVHandleFinalizeVNetRootCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CREATE:
|
|
NtStatus = MRxDAVHandleCreateCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_QUERYDIR:
|
|
NtStatus = MRxDAVHandleQueryDirCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CLOSESRVOPEN:
|
|
NtStatus = MRxDAVHandleCloseSrvOpenCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_SETFILEINFORMATION:
|
|
NtStatus = MRxDAVHandleSetFileInfoCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_CLEANUPFOBX:
|
|
NtStatus = MRxDAVHandleCleanupFobxCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_RENAME:
|
|
NtStatus = MRxDAVHandleRenameCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_QUERYFILEINFORMATION:
|
|
NtStatus = MRxDAVHandleQueryFileInfoCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
case DAV_MINIRDR_ENTRY_FROM_REFRESHTHELOCK:
|
|
NtStatus = MRxDAVHandleLockRefreshCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
default:
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: ERROR: MRxDAVCancelTheContext: EntryPoint: %d\n",
|
|
PsGetCurrentThreadId(), DavContext->EntryPoint));
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
}
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleGeneralCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the some requests which has been cancelled.
|
|
Its called by those rotuines whose completion is straight forward and does
|
|
not require any special handling.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PRX_CONTEXT RxContext = NULL;
|
|
|
|
//
|
|
// Only an AsyncOperation which would have returned STATUS_IO_PENDING
|
|
// can be cancelled by a user.
|
|
//
|
|
if (UserInitiatedCancel) {
|
|
ASSERT(AsyncEngineContext->AsyncOperation == TRUE);
|
|
}
|
|
|
|
RxContext = AsyncEngineContext->RxContext;
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: MRxDAVHandleGeneralCancellation: "
|
|
"AsyncEngineContext = %08lx, RxContext = %08lx.\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
|
|
//
|
|
// If this cancel operation was initiated by the user, we return
|
|
// STATUS_CANCELLED. If it was initiated by the timeout thread, we return
|
|
// STATUS_IO_TIMEOUT.
|
|
//
|
|
if (UserInitiatedCancel) {
|
|
AsyncEngineContext->Status = STATUS_CANCELLED;
|
|
} else {
|
|
AsyncEngineContext->Status = STATUS_IO_TIMEOUT;
|
|
}
|
|
|
|
AsyncEngineContext->Information = 0;
|
|
|
|
//
|
|
// We take different course of action depending upon whether this request
|
|
// was a synchronous or an asynchronous request.
|
|
//
|
|
if (AsyncEngineContext->AsyncOperation) {
|
|
//
|
|
// Complete the request by calling RxCompleteRequest.
|
|
//
|
|
RxContext->CurrentIrp->IoStatus.Status = AsyncEngineContext->Status;
|
|
RxContext->CurrentIrp->IoStatus.Information = AsyncEngineContext->Information;
|
|
RxCompleteRequest(RxContext, AsyncEngineContext->Status);
|
|
} else {
|
|
//
|
|
// This was a synchronous request. There is a thread waiting for this
|
|
// request to finish and be signalled. Signal the thread that is waiting
|
|
// after queuing the workitem on the KQueue.
|
|
//
|
|
RxSignalSynchronousWaiter(RxContext);
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleQueryDirCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the QueryDirectory request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleQueryDirCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCloseSrvOpenCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the CloseSrvOpen request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PMRX_FCB Fcb = AsyncEngineContext->RxContext->pRelevantSrvOpen->pFcb;
|
|
PWEBDAV_FCB DavFcb = MRxDAVGetFcbExtension(Fcb);
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleCloseSrvOpenCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
//
|
|
// If we had reset FileWasModified to 0 in the FormatCloseSrvOpen function,
|
|
// then we need to reset it to 1.
|
|
//
|
|
if (DavFcb->FileModifiedBitReset) {
|
|
InterlockedExchange(&(DavFcb->FileWasModified), 1);
|
|
DavFcb->FileModifiedBitReset = FALSE;
|
|
}
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleSetFileInfoCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the SetFileInfo request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleSetFileInfoCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCreateCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the Create request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleCreateCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCreateSrvCallCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the CreateSrvCall request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PRX_CONTEXT RxContext = NULL;
|
|
PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = NULL;
|
|
PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = NULL;
|
|
PMRX_SRV_CALL SrvCall = NULL;
|
|
PWEBDAV_SRV_CALL DavSrvCall = NULL;
|
|
|
|
RxContext = AsyncEngineContext->RxContext;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleCreateSrvCallCancellation: "
|
|
"AsyncEngineContext = %08lx, RxContext = %08lx.\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
|
|
//
|
|
// A CreateSrvCall operation is always Async.
|
|
//
|
|
ASSERT(AsyncEngineContext->AsyncOperation == TRUE);
|
|
|
|
SCCBC = (PMRX_SRVCALL_CALLBACK_CONTEXT)RxContext->MRxContext[1];
|
|
ASSERT(SCCBC != NULL);
|
|
SrvCalldownStructure = SCCBC->SrvCalldownStructure;
|
|
ASSERT(SrvCalldownStructure != NULL);
|
|
SrvCall = SrvCalldownStructure->SrvCall;
|
|
ASSERT(SrvCall != NULL);
|
|
|
|
//
|
|
// We allocated memory for it, so it better not be NULL.
|
|
//
|
|
DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
|
|
ASSERT(DavSrvCall != NULL);
|
|
|
|
if (DavSrvCall->SCAlreadyInitialized) {
|
|
ASSERT(RxContext->MRxContext[2] != NULL);
|
|
SeDeleteClientSecurity((PSECURITY_CLIENT_CONTEXT)RxContext->MRxContext[2]);
|
|
RxFreePool(RxContext->MRxContext[2]);
|
|
RxContext->MRxContext[2] = NULL;
|
|
DavSrvCall->SCAlreadyInitialized = FALSE;
|
|
}
|
|
|
|
//
|
|
// Set the status in the callback structure. If a CreateSrvCall is being
|
|
// cancelled, this implies that it is being done by the timeout thread
|
|
// since a user can never cancel a create request. Hence the status we set
|
|
// is STATUS_IO_TIMEOUT.
|
|
//
|
|
ASSERT(UserInitiatedCancel == FALSE);
|
|
SCCBC->Status = STATUS_IO_TIMEOUT;
|
|
|
|
//
|
|
// Call the callback function supplied by RDBSS.
|
|
//
|
|
SrvCalldownStructure->CallBack(SCCBC);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleSrvCallFinalizeCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the SrvCallFinalize request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleSrvCallFinalizeCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCreateVNetRootCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the CreateVNetRoot request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PRX_CONTEXT RxContext = NULL;
|
|
PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
|
|
PMRX_V_NET_ROOT VNetRoot = NULL;
|
|
|
|
RxContext = AsyncEngineContext->RxContext;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleCreateVNetRootCancellation: "
|
|
"AsyncEngineContext = %08lx, RxContext = %08lx.\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
|
|
//
|
|
// The VNetRoot pointer is stored in the MRxContext[1] pointer of the
|
|
// RxContext structure. This is done in the MRxDAVCreateVNetRoot
|
|
// function.
|
|
//
|
|
VNetRoot = (PMRX_V_NET_ROOT)RxContext->MRxContext[1];
|
|
DavVNetRoot = MRxDAVGetVNetRootExtension(VNetRoot);
|
|
ASSERT(DavVNetRoot != NULL);
|
|
|
|
DavVNetRoot->createVNetRootUnSuccessful = TRUE;
|
|
|
|
//
|
|
// Set the status in the AsyncEngineContext. If a CreateSrvCall is being
|
|
// cancelled, this implies that it is being done by the timeout thread
|
|
// since a user can never cancel a create request. Hence the status we set
|
|
// is STATUS_IO_TIMEOUT.
|
|
//
|
|
ASSERT(UserInitiatedCancel == FALSE);
|
|
AsyncEngineContext->Status = STATUS_IO_TIMEOUT;
|
|
|
|
//
|
|
// This was a synchronous request. There is a thread waiting for this
|
|
// request to finish and be signalled. Signal the thread that is waiting
|
|
// after queuing the workitem on the KQueue.
|
|
//
|
|
ASSERT(AsyncEngineContext->AsyncOperation == FALSE);
|
|
RxSignalSynchronousWaiter(RxContext);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleFinalizeVNetRootCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the FinalizeVNetRoot request which has
|
|
been cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleFinalizeVNetRootCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleCleanupFobxCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the CleanupFobx request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleCleanupFobxCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleRenameCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the Rename request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleRenameCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleQueryFileInfoCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the QueryFileInfo request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleQueryFileInfoCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVHandleLockRefreshCancellation(
|
|
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
|
|
BOOL UserInitiatedCancel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of the QueryFileInfo request which has been
|
|
cancelled.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The DAV Redir's context describing the CreateSrvCall
|
|
operation.
|
|
|
|
UserInitiatedCancel - TRUE - This cancel was initiated by a user request.
|
|
FALSE - This cancel was initiated by the timeout
|
|
mechanism.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVHandleLockRefreshCancellation: "
|
|
"AsyncEngineContext = %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext));
|
|
|
|
NtStatus = MRxDAVHandleGeneralCancellation(AsyncEngineContext, UserInitiatedCancel);
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
MRxDAVRefreshTheServerLocks(
|
|
PVOID DummyContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the timer thread to refresh the LOCKs that have
|
|
been taken on various files which are shared on different servers. The
|
|
LOCKs are granted by the server for a limited period of time and if the
|
|
client wants to hold the LOCK for a longer period than that, it needs to
|
|
send a refresh request to the server.
|
|
|
|
Arguments:
|
|
|
|
DummyContext - A dummy context that is supplied.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PLIST_ENTRY TokenListEntry = NULL;
|
|
PWEBDAV_LOCK_TOKEN_ENTRY LockTokenEntry = NULL;
|
|
BOOL lockAcquired = FALSE;
|
|
LARGE_INTEGER CurrentSystemTickCount, TickCountDifference;
|
|
LARGE_INTEGER LockTimeoutValueInTickCount;
|
|
PRX_CONTEXT RxContext = NULL;
|
|
PRDBSS_DEVICE_OBJECT RxDeviceObject = (PRDBSS_DEVICE_OBJECT)MRxDAVDeviceObject;
|
|
|
|
ExAcquireResourceExclusiveLite(&(LockTokenEntryListLock), TRUE);
|
|
lockAcquired = TRUE;
|
|
|
|
TokenListEntry = LockTokenEntryList.Flink;
|
|
|
|
while ( TokenListEntry != &(LockTokenEntryList) ) {
|
|
|
|
//
|
|
// Get the pointer to the WEBDAV_LOCK_TOKEN_ENTRY structure.
|
|
//
|
|
LockTokenEntry = CONTAINING_RECORD(TokenListEntry,
|
|
WEBDAV_LOCK_TOKEN_ENTRY,
|
|
listEntry);
|
|
|
|
TokenListEntry = TokenListEntry->Flink;
|
|
|
|
//
|
|
// An RxContext is required for a request to be reflected up.
|
|
//
|
|
RxContext = RxCreateRxContext(NULL, RxDeviceObject, 0);
|
|
if (RxContext == NULL) {
|
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVRefreshTheServerLocks/RxCreateRxContext: "
|
|
"NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
//
|
|
// Calculate the timeout value in TickCount (100 nano seconds) using
|
|
// the timeout value in seconds). Step1 below calculates the number of
|
|
// ticks that happen in one second. Step2 below calculates the number
|
|
// of ticks in LockTimeoutValueInSec.
|
|
//
|
|
LockTimeoutValueInTickCount.QuadPart = ( (1000 * 1000 * 10) / KeQueryTimeIncrement() );
|
|
LockTimeoutValueInTickCount.QuadPart *= LockTokenEntry->LockTimeOutValueInSec;
|
|
|
|
KeQueryTickCount( &(CurrentSystemTickCount) );
|
|
|
|
//
|
|
// Get the time elapsed (in system tick counts) since the time this
|
|
// LockTokenEntry was created.
|
|
//
|
|
TickCountDifference.QuadPart = (CurrentSystemTickCount.QuadPart - LockTokenEntry->CreationTimeInTickCount.QuadPart);
|
|
|
|
//
|
|
// If the time difference betweeen the current time and the last time
|
|
// this LOCK was refreshed is greater than LockTimeOut/2, we need to
|
|
// refresh this LOCK. To refresh the LOCK, we need to go to the usermode
|
|
// to send the request. Also, we only refresh this lock if the value of
|
|
// LockTokenEntry->ShouldThisEntryBeRefreshed is TRUE.
|
|
//
|
|
if ( LockTokenEntry->ShouldThisEntryBeRefreshed &&
|
|
TickCountDifference.QuadPart > (LockTimeoutValueInTickCount.QuadPart / 2) ) {
|
|
|
|
//
|
|
// We need to store the LockTokenEntry in the RxContext since it
|
|
// will be needed to impersonate the client and refresh the LOCK.
|
|
//
|
|
RxContext->MRxContext[1] = LockTokenEntry;
|
|
|
|
NtStatus = UMRxAsyncEngOuterWrapper(RxContext,
|
|
SIZEOF_DAV_SPECIFIC_CONTEXT,
|
|
MRxDAVFormatTheDAVContext,
|
|
DAV_MINIRDR_ENTRY_FROM_REFRESHTHELOCK,
|
|
MRxDAVRefreshTheServerLocksContinuation,
|
|
"MRxDAVRefreshTheServerLocks");
|
|
if (NtStatus != ERROR_SUCCESS) {
|
|
//
|
|
// Even if we fail to refresh one LOCK we continue to refresh
|
|
// the remaining LOCKs in the LockTokenEntryList.
|
|
//
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVRefreshTheServerLocks/UMRxAsyncEngOuterWrapper: "
|
|
"LockTokenEntry = %08lx, NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), LockTokenEntry, NtStatus));
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// We take the reference out on the RxContext we allocated above. If
|
|
// NtStatus is not STATUS_CANCELLED, this also lands up freeing the
|
|
// RxContext since this would be the last reference on the RxContext.
|
|
// If NtStatus is STATUS_CANCELLED then the AsyncEngineContext associated
|
|
// with this RxContext might have a reference on this RxContext (if the
|
|
// request hasn't come back from the usermode). In such a scenario, the
|
|
// RxContext is freed up when request comes back from the usermode.
|
|
//
|
|
RxDereferenceAndDeleteRxContext(RxContext);
|
|
|
|
}
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
if (lockAcquired) {
|
|
ExReleaseResourceLite(&(LockTokenEntryListLock));
|
|
lockAcquired = FALSE;
|
|
}
|
|
|
|
//
|
|
// Before we exit, we need to set QueueLockRefreshWorkItem to TRUE so
|
|
// that a new WorkItem can get queued to refresh the active locks.
|
|
//
|
|
ExAcquireResourceExclusiveLite(&(QueueLockRefreshWorkItemLock), TRUE);
|
|
QueueLockRefreshWorkItem = TRUE;
|
|
ExReleaseResourceLite(&(QueueLockRefreshWorkItemLock));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVRefreshTheServerLocksContinuation(
|
|
UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the continuation routine which refreshes a LOCK.
|
|
|
|
Arguments:
|
|
|
|
AsyncEngineContext - The Reflectors context.
|
|
|
|
RxContext - The RDBSS context.
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: Entering MRxDAVRefreshTheServerLocksContinuation\n",
|
|
PsGetCurrentThreadId()));
|
|
|
|
DavDbgTrace(DAV_TRACE_CONTEXT,
|
|
("%ld: MRxDAVRefreshTheServerLocksContinuation: "
|
|
"AsyncEngineContext: %08lx, RxContext: %08lx\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
|
|
//
|
|
// Try usermode.
|
|
//
|
|
NtStatus = UMRxSubmitAsyncEngUserModeRequest(
|
|
UMRX_ASYNCENGINE_ARGUMENTS,
|
|
MRxDAVFormatUserModeRefreshTheServerLockRequest,
|
|
MRxDAVPrecompleteUserModeRefreshTheServerLockRequest
|
|
);
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: Leaving MRxDAVFinalizeSrvCallContinuation with NtStatus"
|
|
" = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxDAVFormatUserModeRefreshTheServerLockRequest(
|
|
IN UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
|
|
IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
|
|
IN ULONG WorkItemLength,
|
|
OUT PULONG_PTR ReturnedLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine formats the LOCK refresh request being sent to the user mode
|
|
for processing.
|
|
|
|
Arguments:
|
|
|
|
RxContext - The RDBSS context.
|
|
|
|
AsyncEngineContext - The reflctor's context.
|
|
|
|
WorkItem - The work item buffer.
|
|
|
|
WorkItemLength - The length of the work item buffer.
|
|
|
|
ReturnedLength -
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
|
|
PWEBDAV_LOCK_TOKEN_ENTRY LockTokenEntry = NULL;
|
|
PDAV_USERMODE_LOCKREFRESH_REQUEST LockRefreshRequest = NULL;
|
|
PBYTE ServerName = NULL, PathName = NULL, OpaqueLockToken = NULL;
|
|
ULONG ServerNameLengthInBytes = 0, PathNameLengthInBytes = 0, OpaqueLockTokenLengthInBytes = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: Entering MRxDAVFormatUserModeRefreshTheServerLockRequest.\n",
|
|
PsGetCurrentThreadId()));
|
|
|
|
DavDbgTrace(DAV_TRACE_CONTEXT,
|
|
("%ld: MRxDAVFormatUserModeRefreshTheServerLockRequest: "
|
|
"AsyncEngineContext: %08lx, RxContext: %08lx.\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
|
|
LockRefreshRequest = &(DavWorkItem->LockRefreshRequest);
|
|
|
|
//
|
|
// LockTokenEntry was set to MRxContext[1] in the MRxDAVRefreshTheServerLocks
|
|
// routine.
|
|
//
|
|
LockTokenEntry = (PWEBDAV_LOCK_TOKEN_ENTRY)RxContext->MRxContext[1];
|
|
|
|
DavWorkItem->WorkItemType = UserModeLockRefresh;
|
|
|
|
//
|
|
// Copy the ServerName.
|
|
//
|
|
|
|
ServerNameLengthInBytes = (1 + wcslen(LockTokenEntry->ServerName)) * sizeof(WCHAR);
|
|
ServerName = UMRxAllocateSecondaryBuffer(AsyncEngineContext,
|
|
ServerNameLengthInBytes);
|
|
if (ServerName == NULL) {
|
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("ld: MRxDAVFormatUserModeRefreshTheServerLockRequest/"
|
|
"UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
LockRefreshRequest->ServerName = (PWCHAR)ServerName;
|
|
|
|
wcscpy(LockRefreshRequest->ServerName, LockTokenEntry->ServerName);
|
|
|
|
//
|
|
// Copy the PathName.
|
|
//
|
|
|
|
PathNameLengthInBytes = (1 + wcslen(LockTokenEntry->PathName)) * sizeof(WCHAR);
|
|
PathName = UMRxAllocateSecondaryBuffer(AsyncEngineContext,
|
|
PathNameLengthInBytes);
|
|
if (PathName == NULL) {
|
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("ld: MRxDAVFormatUserModeRefreshTheServerLockRequest/"
|
|
"UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
LockRefreshRequest->PathName = (PWCHAR)PathName;
|
|
|
|
wcscpy(LockRefreshRequest->PathName, LockTokenEntry->PathName);
|
|
|
|
//
|
|
// Copy the OpaqueLockToken.
|
|
//
|
|
|
|
OpaqueLockTokenLengthInBytes = (1 + wcslen(LockTokenEntry->OpaqueLockToken)) * sizeof(WCHAR);
|
|
OpaqueLockToken = UMRxAllocateSecondaryBuffer(AsyncEngineContext,
|
|
OpaqueLockTokenLengthInBytes);
|
|
if (OpaqueLockToken == NULL) {
|
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("ld: MRxDAVFormatUserModeRefreshTheServerLockRequest/"
|
|
"UMRxAllocateSecondaryBuffer: ERROR: NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
LockRefreshRequest->OpaqueLockToken = (PWCHAR)OpaqueLockToken;
|
|
|
|
wcscpy(LockRefreshRequest->OpaqueLockToken, LockTokenEntry->OpaqueLockToken);
|
|
|
|
LockRefreshRequest->ServerID = LockTokenEntry->ServerID;
|
|
|
|
LockRefreshRequest->LogonID.LowPart = LockTokenEntry->LogonID.LowPart;
|
|
LockRefreshRequest->LogonID.HighPart = LockTokenEntry->LogonID.HighPart;
|
|
|
|
//
|
|
// Impersonate the client who initiated the request. If we fail to
|
|
// impersonate, tough luck.
|
|
//
|
|
NtStatus = UMRxImpersonateClient(LockTokenEntry->SecurityClientContext, WorkItemHeader);
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: ERROR: MRxDAVFormatUserModeRefreshTheServerLockRequest/"
|
|
"UMRxImpersonateClient. NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: Leaving MRxDAVFormatUserModeRefreshTheServerLockRequest "
|
|
"with NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MRxDAVPrecompleteUserModeRefreshTheServerLockRequest(
|
|
UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
|
|
PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
|
|
ULONG WorkItemLength,
|
|
BOOL OperationCancelled
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The precompletion routine for the LOCK refresh request.
|
|
|
|
Arguments:
|
|
|
|
RxContext - The RDBSS context.
|
|
|
|
AsyncEngineContext - The reflctor's context.
|
|
|
|
WorkItem - The work item buffer.
|
|
|
|
WorkItemLength - The length of the work item buffer.
|
|
|
|
OperationCancelled - TRUE if this operation was cancelled by the user.
|
|
|
|
Return Value:
|
|
|
|
TRUE - UMRxAsyncEngineCalldownIrpCompletion is called by the function
|
|
UMRxCompleteUserModeRequest after we return.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)WorkItemHeader;
|
|
PDAV_USERMODE_LOCKREFRESH_REQUEST LockRefreshRequest = NULL;
|
|
PDAV_USERMODE_LOCKREFRESH_RESPONSE LockRefreshResponse = NULL;
|
|
PWEBDAV_LOCK_TOKEN_ENTRY LockTokenEntry = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: Entering MRxDAVPrecompleteUserModeRefreshTheServerLockRequest\n",
|
|
PsGetCurrentThreadId()));
|
|
|
|
DavDbgTrace(DAV_TRACE_CONTEXT,
|
|
("%ld: MRxDAVPrecompleteUserModeRefreshTheServerLockRequest: "
|
|
"AsyncEngineContext: %08lx, RxContext: %08lx.\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
|
|
LockRefreshRequest = &(DavWorkItem->LockRefreshRequest);
|
|
LockRefreshResponse = &(DavWorkItem->LockRefreshResponse);
|
|
|
|
if (OperationCancelled) {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: MRxDAVPrecompleteUserModeRefreshTheServerLockRequest: Operation Cancelled. "
|
|
"AsyncEngineContext = %08lx, RxContext = %08lx.\n",
|
|
PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
|
|
}
|
|
|
|
//
|
|
// We need to free up the heap we allocated in the format routine.
|
|
//
|
|
|
|
if (LockRefreshRequest->ServerName != NULL) {
|
|
|
|
NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
|
|
(PBYTE)LockRefreshRequest->ServerName);
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: ERROR: MRxDAVPrecompleteUserModeRefreshTheServerLockRequest/"
|
|
"UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
}
|
|
|
|
}
|
|
|
|
if (LockRefreshRequest->PathName != NULL) {
|
|
|
|
NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
|
|
(PBYTE)LockRefreshRequest->PathName);
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: ERROR: MRxDAVPrecompleteUserModeRefreshTheServerLockRequest/"
|
|
"UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
}
|
|
|
|
}
|
|
|
|
if (LockRefreshRequest->OpaqueLockToken != NULL) {
|
|
|
|
NtStatus = UMRxFreeSecondaryBuffer(AsyncEngineContext,
|
|
(PBYTE)LockRefreshRequest->OpaqueLockToken);
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("%ld: ERROR: MRxDAVPrecompleteUserModeRefreshTheServerLockRequest/"
|
|
"UMRxFreeSecondaryBuffer: NtStatus = %08lx.\n",
|
|
PsGetCurrentThreadId(), NtStatus));
|
|
}
|
|
|
|
}
|
|
|
|
if (!OperationCancelled) {
|
|
|
|
//
|
|
// LockTokenEntry was set to MRxContext[1] in the MRxDAVRefreshTheServerLocks
|
|
// routine.
|
|
//
|
|
LockTokenEntry = (PWEBDAV_LOCK_TOKEN_ENTRY)RxContext->MRxContext[1];
|
|
|
|
//
|
|
// Get the new timeout value returned by the server.
|
|
//
|
|
LockTokenEntry->LockTimeOutValueInSec = LockRefreshResponse->NewTimeOutInSec;
|
|
|
|
//
|
|
// Set the current system time as the new creation time of the entry.
|
|
//
|
|
KeQueryTickCount( &(LockTokenEntry->CreationTimeInTickCount) );
|
|
|
|
}
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("%ld: Leaving MRxDAVPrecompleteUserModeRefreshTheServerLockRequest\n",
|
|
PsGetCurrentThreadId()));
|
|
|
|
return TRUE;
|
|
}
|
|
|