Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1555 lines
52 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
devfcb.c
Abstract:
This module implements all ioctls and fsctls that can be applied to
a device fcb.
Author:
Joe Linn
Rohan Kumar [RohanK] 13-March-1999
--*/
#include "precomp.h"
#pragma hdrstop
#include "fsctlbuf.h"
#include "webdav.h"
//
// Mentioned below are the prototypes of functions tht are used only within
// this module (file). These functions should not be exposed outside.
//
NTSTATUS
MRxDAVOuterStart(
IN PRX_CONTEXT RxContext
);
NTSTATUS
MRxDAVOuterStop(
IN PRX_CONTEXT RxContext
);
NTSTATUS
MRxDAVDeleteConnection(
IN PRX_CONTEXT RxContext,
OUT PBOOLEAN PostToFsp
);
NTSTATUS
MRxDavDeleteConnection(
IN OUT PRX_CONTEXT RxContext
);
VOID
MRxDAVGetLockOwnerFromFileName(
IN PWEBDAV_DEVICE_OBJECT MRxDAVDeviceObject,
IN OUT PWCHAR InputBuffer,
IN ULONG InputBufferLength,
OUT PWCHAR OutputBuffer,
IN ULONG OutputBufferLength,
OUT PIO_STATUS_BLOCK IoStatus
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, MRxDAVDevFcbXXXControlFile)
#pragma alloc_text(PAGE, MRxDAVOuterStart)
#pragma alloc_text(PAGE, MRxDAVStart)
#pragma alloc_text(PAGE, MRxDAVOuterStop)
#pragma alloc_text(PAGE, MRxDAVStop)
#pragma alloc_text(PAGE, MRxDAVDeleteConnection)
#pragma alloc_text(PAGE, MRxDAVFastIoDeviceControl)
#pragma alloc_text(PAGE, MRxDAVFormatTheDAVContext)
#pragma alloc_text(PAGE, MRxDavDeleteConnection)
#endif
//
// Implementation of functions begins here.
//
NTSTATUS
MRxDAVDevFcbXXXControlFile(
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine handles all the device FCB related FSCTL's in the mini rdr.
Arguments:
RxContext - Describes the Fsctl and Context.
Return Value:
STATUS_SUCCESS - The Startup sequence was successfully completed. Any other
value indicates the appropriate error in the startup
sequence.
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
RxCaptureFobx;
UCHAR MajorFunctionCode = RxContext->MajorFunction;
PLOWIO_CONTEXT LowIoContext = &(RxContext->LowIoContext);
UCHAR MinorFunctionCode = LowIoContext->ParamsFor.FsCtl.MinorFunction;
ULONG ControlCode = LowIoContext->ParamsFor.FsCtl.FsControlCode;
LUID LocalServiceLogonID = LOCALSERVICE_LUID, ClientLogonID;
LUID SystemLogonID = SYSTEM_LUID;
BOOLEAN IsInLocalServiceProcess = FALSE, IsInSystemProcess = FALSE;
SECURITY_SUBJECT_CONTEXT ClientContext;
PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL;
PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
PVOID OutputBuffer = NULL;
PAGED_CODE();
DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject);
UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject);
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Entering MRxDAVDevFcbXXXControlFile!!!!\n",
PsGetCurrentThreadId()));
DavDbgTrace(DAV_TRACE_CONTEXT,
("%ld: MRxDAVDevFcbXXXControlFile: RxContext: %08lx.\n",
PsGetCurrentThreadId(), RxContext));
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVDevFcbXXXControlFile: MajorFunctionCode = %d, MinorFunctionCode = %d, ControlCode = %08lx\n",
PsGetCurrentThreadId(), MajorFunctionCode, MinorFunctionCode, ControlCode));
SeCaptureSubjectContext( &(ClientContext) );
SeLockSubjectContext( &(ClientContext) );
NtStatus = SeQueryAuthenticationIdToken(SeQuerySubjectContextToken(&(ClientContext)),
&(ClientLogonID));
if (NtStatus == STATUS_SUCCESS) {
IsInLocalServiceProcess = RtlEqualLuid( &(ClientLogonID), &(LocalServiceLogonID) );
IsInSystemProcess = RtlEqualLuid( &(ClientLogonID), &(SystemLogonID) );
} else {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile/SeQueryAuthenticationIdToken: "
"NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
}
SeUnlockSubjectContext( &(ClientContext) );
SeReleaseSubjectContext( &(ClientContext) );
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVDevFcbXXXControlFile: IsInLocalServiceProcess = %d, IsInSystemProcess = %d\n",
PsGetCurrentThreadId(), IsInLocalServiceProcess, IsInSystemProcess));
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVDevFcbXXXControlFile: ClientLogonID.HighPart = %x, ClientLogonID.LowPart = %x\n",
PsGetCurrentThreadId(), ClientLogonID.HighPart, ClientLogonID.LowPart));
switch (MajorFunctionCode) {
case IRP_MJ_FILE_SYSTEM_CONTROL: {
switch (MinorFunctionCode) {
case IRP_MN_USER_FS_REQUEST: {
switch (ControlCode) {
case FSCTL_UMRX_START:
if (!IsInLocalServiceProcess && !IsInSystemProcess) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
PsGetCurrentThreadId()));
NtStatus = STATUS_ACCESS_DENIED;
goto EXIT_THE_FUNCTION;
}
ASSERT (!capFobx);
NtStatus = MRxDAVOuterStart(RxContext);
break;
case FSCTL_UMRX_STOP:
if (!IsInLocalServiceProcess && !IsInSystemProcess) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(2)\n",
PsGetCurrentThreadId()));
NtStatus = STATUS_ACCESS_DENIED;
goto EXIT_THE_FUNCTION;
}
ASSERT (!capFobx);
if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) {
return STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
} else {
NtStatus = MRxDAVOuterStop(RxContext);
}
break;
case FSCTL_DAV_DELETE_CONNECTION:
NtStatus = MRxDavDeleteConnection(RxContext);
break;
default:
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: "
"ControlCode = %d\n",
PsGetCurrentThreadId(), ControlCode));
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
break;
default :
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: "
"MinorFunctionCode = %d\n",
PsGetCurrentThreadId(), MinorFunctionCode));
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
break;
case IRP_MJ_DEVICE_CONTROL:
case IRP_MJ_INTERNAL_DEVICE_CONTROL: {
switch (ControlCode) {
case IOCTL_UMRX_RELEASE_THREADS:
if (!IsInLocalServiceProcess && !IsInSystemProcess) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
PsGetCurrentThreadId()));
NtStatus = STATUS_ACCESS_DENIED;
goto EXIT_THE_FUNCTION;
}
UMRxReleaseCapturedThreads(UMRefDeviceObject);
RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
RxContext->CurrentIrp->IoStatus.Information = 0;
NtStatus = STATUS_SUCCESS;
break;
case IOCTL_UMRX_GET_REQUEST:
case IOCTL_UMRX_RESPONSE_AND_REQUEST:
case IOCTL_UMRX_RESPONSE:
if (!IsInLocalServiceProcess && !IsInSystemProcess) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
PsGetCurrentThreadId()));
NtStatus = STATUS_ACCESS_DENIED;
goto EXIT_THE_FUNCTION;
}
//
// The above IOCTLs are "METHOD_OUT_DIRECT" type.
// The InputBuffer is stored at this location:
// "RxContext->CurrentIrp->AssociatedIrp.SystemBuffer"
// The OutputBuffer is an MDL stored at this location:
// "RxContext->CurrentIrp->MdlAddress"
//
if (RxContext->CurrentIrp->MdlAddress != NULL) {
OutputBuffer = MmGetSystemAddressForMdlSafe(RxContext->CurrentIrp->MdlAddress, LowPagePriority);
if (OutputBuffer == NULL) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile/MmGetSystemAddressForMdlSafe\n",
PsGetCurrentThreadId()));
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EXIT_THE_FUNCTION;
}
}
UMRxAssignWork(UMRefDeviceObject,
RxContext->CurrentIrp->AssociatedIrp.SystemBuffer,
RxContext->CurrentIrpSp->Parameters.DeviceIoControl.InputBufferLength,
OutputBuffer,
RxContext->CurrentIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
&(RxContext->CurrentIrp->IoStatus));
NtStatus = RxContext->CurrentIrp->IoStatus.Status;
break;
case IOCTL_UMRX_GET_LOCK_OWNER:
MRxDAVGetLockOwnerFromFileName(DavDeviceObject,
RxContext->CurrentIrp->AssociatedIrp.SystemBuffer,
RxContext->CurrentIrpSp->Parameters.DeviceIoControl.InputBufferLength,
RxContext->CurrentIrp->AssociatedIrp.SystemBuffer,
RxContext->CurrentIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
&(RxContext->CurrentIrp->IoStatus));
NtStatus = RxContext->CurrentIrp->IoStatus.Status;
break;
default :
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: ControlCode = %d\n",
PsGetCurrentThreadId(), ControlCode));
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
break;
default:
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVDevFcbXXXControlFile: "
"MajorFunction = %d\n",
PsGetCurrentThreadId(), MajorFunctionCode));
NtStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
EXIT_THE_FUNCTION:
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Leaving MRxDAVDevFcbXXXControlFile with NtStatus = "
"%08lx.\n", PsGetCurrentThreadId(), NtStatus));
//
// This suppresses the second call to my lowio Fsctl routine.
//
RxContext->pFobx = NULL;
return(NtStatus);
}
NTSTATUS
MRxDAVOuterStart(
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine starts the Mini-Redir if it hasn't been started already.
Arguments:
RxContext - Describes the Fsctl and Context.
Return Value:
STATUS_SUCCESS or the appropriate error code.
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL;
PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
PLOWIO_CONTEXT LowIoContext = NULL;
PDAV_USERMODE_DATA DavUserModeData = NULL;
ULONG DavUserModeDataLength = 0;
PAGED_CODE();
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Entering MRxDAVOuterStart!!!!\n",
PsGetCurrentThreadId()));
DavDbgTrace(DAV_TRACE_CONTEXT,
("%ld: MRxDAVOuterStart: RxContext: %08lx.\n",
PsGetCurrentThreadId(), RxContext));
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStart: Try to Start the Mini-Redir\n",
PsGetCurrentThreadId()));
DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject);
UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject);
LowIoContext= &(RxContext->LowIoContext);
//
// The WinInet cache path and the process id are stored in the input buffer
// of the FSCTL.
//
DavUserModeData = (PDAV_USERMODE_DATA)LowIoContext->ParamsFor.FsCtl.pInputBuffer;
ASSERT(DavUserModeData != NULL);
DavUserModeDataLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
ASSERT(DavUserModeDataLength == sizeof(DAV_USERMODE_DATA));
//
// Set the DeviceFcb, now that we have an RxContext.
//
DavDeviceObject->CachedRxDeviceFcb = RxContext->pFcb;
//
// We call ExAcquireFastMutexUnsafe instead of ExAcquireFastMutex because the
// APCs have already been disabled by the FsrtlEnterFileSystem() call in the
// RxFsdCommonDispatch function. This is done because a ExAcquireFastMutex
// raises the IRQL level to APC_LEVEL (1) which is wrong since we are calling
// into RxStartMiniRedir which calls FsrtlRegisterUncProvider which lands
// up calling into the Dav MiniRedir again. If the IRQL level is raised here,
// the MiniRedir will get called at a raised IRQL which is wrong.
//
ExAcquireFastMutexUnsafe( &(MRxDAVSerializationMutex) );
try {
if (DavDeviceObject->IsStarted) {
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStart: Mini-Redir already started.\n",
PsGetCurrentThreadId()));
try_return(NtStatus = STATUS_REDIRECTOR_STARTED);
}
NtStatus = RxStartMinirdr(RxContext, &RxContext->PostRequest);
if (NtStatus == STATUS_SUCCESS) {
DavDeviceObject->IsStarted = TRUE;
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStart: Mini-Redir started.\n",
PsGetCurrentThreadId()));
//
// Copy the DavWinInetCachePath value into the global variable. This
// value is used to satisy the volume relalted queries.
//
wcscpy(DavWinInetCachePath, DavUserModeData->WinInetCachePath);
//
// Copy the ProcessId of the svchost.exe process that loads the
// webclnt.dll.
//
DavSvcHostProcessId = DavUserModeData->ProcessId;
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStart: DavWinInetCachePath = %ws, DavSvcHostProcessId = %x\n",
PsGetCurrentThreadId(), DavWinInetCachePath, DavSvcHostProcessId));
//
// Start the timer thread. This thread wakes up every few minutes
// (RequestTimeoutValueInSec) and cancels all the requests that
// have not completed for more than RequestTimeoutValueInSec.
//
NtStatus = PsCreateSystemThread(&(TimerThreadHandle),
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
MRxDAVContextTimerThread,
NULL);
if (NtStatus != STATUS_SUCCESS) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVOuterStart/PsCreateSystemThread: NtStatus"
" = %08lx\n", PsGetCurrentThreadId(), NtStatus));
}
} else {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVOuterStart/RxStartMinirdr: NtStatus"
" = %08lx\n", PsGetCurrentThreadId(), NtStatus));
try_return(NtStatus);
}
try_exit: NOTHING;
} finally {
//
// Since we called ExAcquireFastMutexUnsafe to acquire this mutex, we
// call ExReleaseFastMutexUnsafe to release it.
//
ExReleaseFastMutexUnsafe( &(MRxDAVSerializationMutex) );
}
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Leaving MRxDAVOuterStart with NtStatus = %08lx.\n",
PsGetCurrentThreadId(), NtStatus));
return(NtStatus);
}
NTSTATUS
MRxDAVStart(
PRX_CONTEXT RxContext,
IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
)
/*++
Routine Description:
This routine completes the initialization of the mini redirector fromn the
RDBSS perspective. Note that this is different from the initialization done
in DriverEntry. Any initialization that depends on RDBSS should be done as
part of this routine while the initialization that is independent of RDBSS
should be done in the DriverEntry routine.
Arguments:
RxContext - Supplies the Irp that was used to startup the rdbss
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PAGED_CODE();
return NtStatus;
}
NTSTATUS
MRxDAVOuterStop(
IN PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine stops the Mini-Redir if it has been started.
Arguments:
RxContext - Describes the Fsctl and Context.
Return Value:
STATUS_SUCCESS or the appropriate error code.
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL;
PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
PVOID HeapHandle = NULL;
PLIST_ENTRY pFirstListEntry = NULL;
PUMRX_SHARED_HEAP sharedHeap = NULL;
BOOLEAN TimerState = FALSE;
PAGED_CODE();
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Entering MRxDAVOuterStop!!!!\n",
PsGetCurrentThreadId()));
DavDbgTrace(DAV_TRACE_CONTEXT,
("%ld: MRxDAVOuterStop: RxContext: %08lx.\n",
PsGetCurrentThreadId(), RxContext));
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStop: Try to Stop the Mini-Redir.\n",
PsGetCurrentThreadId()));
DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject);
UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject);
//
// Tell the timer thread that its time to shutdown to its job is done.
//
ExAcquireResourceExclusiveLite(&(MRxDAVTimerThreadLock), TRUE);
if (!TimerThreadShutDown) {
TimerThreadShutDown = TRUE;
//
// Read the state of the timer. If its NOT signalled, call KeSetTimerEx
// with 0 DueTime (2nd argument) to signal it.
//
TimerState = KeReadStateTimer( &(DavTimerObject) );
if (!TimerState) {
LARGE_INTEGER TimeOutNow;
TimeOutNow.QuadPart = 0;
KeSetTimerEx(&(DavTimerObject), TimeOutNow, 0, NULL);
}
ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
//
// We now call MRxDAVCleanUpTheLockConflictList to free up all the
// entries from the global LockConflictEntryList.
//
MRxDAVCleanUpTheLockConflictList(TRUE);
//
// Complete all the currently active contexts.
//
MRxDAVTimeOutTheContexts(TRUE);
} else {
//
// If we have already shutdown the timer thread, then we don't need to
// do it again. Just release the resource and move on.
//
ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
}
//
// Free the list of shared memory heaps. This has to happen in the context
// of the DAV's usermode process. It cannot happen at Unload time since
// unload happens in the context of a system thread.
//
while (!IsListEmpty(&UMRefDeviceObject->SharedHeapList)) {
pFirstListEntry = RemoveHeadList(&UMRefDeviceObject->SharedHeapList);
sharedHeap = (PUMRX_SHARED_HEAP) CONTAINING_RECORD(pFirstListEntry,
UMRX_SHARED_HEAP,
HeapListEntry);
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStop: sharedHeap: %08lx.\n",
PsGetCurrentThreadId(), sharedHeap));
// ASSERT(sharedHeap->HeapAllocationCount == 0);
HeapHandle = RtlDestroyHeap(sharedHeap->Heap);
if (HeapHandle != NULL) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVOuterStop/RtlDestroyHeap.\n",
PsGetCurrentThreadId()));
}
ZwFreeVirtualMemory(NtCurrentProcess(),
&sharedHeap->VirtualMemoryBuffer,
&sharedHeap->VirtualMemoryLength,
MEM_RELEASE);
RxFreePool(sharedHeap);
}
//
// We call ExAcquireFastMutexUnsafe instead of ExAcquireFastMutex because the
// APCs have already been disabled by the FsrtlEnterFileSystem() call in the
// RxFsdCommonDispatch function. This is done because a ExAcquireFastMutex
// raises the IRQL level to APC_LEVEL (1) which is wrong since we are calling
// into RxStartMiniRedir which calls FsrtlRegisterUncProvider which lands
// up calling into the Dav MiniRedir again. If the IRQL level is raised here,
// the MiniRedir will get called at a raised IRQL which is wrong.
//
ExAcquireFastMutexUnsafe(&MRxDAVSerializationMutex);
try {
if (!DavDeviceObject->IsStarted) {
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStop: Mini-Redir not started.\n",
PsGetCurrentThreadId()));
try_return(NtStatus = STATUS_REDIRECTOR_NOT_STARTED);
}
NtStatus = RxStopMinirdr(RxContext, &RxContext->PostRequest);
if (NtStatus == STATUS_SUCCESS) {
DavDeviceObject->IsStarted = FALSE;
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVOuterStop: Mini-Redir stopped.\n",
PsGetCurrentThreadId()));
} else {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVOuterStop/RxStopMinirdr: NtStatus"
" = %08lx\n", PsGetCurrentThreadId(), NtStatus));
try_return(NtStatus);
}
try_exit: NOTHING;
} finally {
//
// Since we called ExAcquireFastMutexUnsafe to acquire this mutex, we
// call ExReleaseFastMutexUnsafe to release it.
//
ExReleaseFastMutexUnsafe(&MRxDAVSerializationMutex);
}
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Leaving MRxDAVOuterStop with NtStatus = %08lx.\n",
PsGetCurrentThreadId(), NtStatus));
return(NtStatus);
}
NTSTATUS
MRxDAVStop(
PRX_CONTEXT RxContext,
IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
)
/*++
Routine Description:
This routine is used to activate the mini redirector from the RDBSS perspective
Arguments:
RxContext - the context that was used to start the mini redirector
Return Value:
RXSTATUS - The return status for the operation
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PAGED_CODE();
return NtStatus;
}
NTSTATUS
MRxDAVDeleteConnection(
IN PRX_CONTEXT RxContext,
OUT PBOOLEAN PostToFsp
)
/*++
Routine Description:
This routine deletes a single vnetroot.
Arguments:
IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers
Return Value:
RXSTATUS
--*/
{
NTSTATUS Status;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
RxCaptureFobx;
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
PNET_ROOT NetRoot;
PV_NET_ROOT VNetRoot;
PAGED_CODE();
if (!Wait) {
*PostToFsp = TRUE;
return(STATUS_PENDING);
}
try {
if (NodeType(capFobx)==RDBSS_NTC_V_NETROOT) {
VNetRoot = (PV_NET_ROOT)capFobx;
NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
} else {
ASSERT(FALSE);
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
NetRoot = (PNET_ROOT)capFobx;
VNetRoot = NULL;
}
Status = RxFinalizeConnection(NetRoot,VNetRoot,TRUE);
try_return(Status);
try_exit:NOTHING;
} finally {
RxDbgTraceUnIndent(-1,Dbg);
}
return Status;
}
BOOLEAN
MRxDAVFastIoDeviceControl(
IN struct _FILE_OBJECT *FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
)
/*++
Routine Description:
This routine handles the Fast I/O path of the WebDav miniredir.
Arguments:
FileObject - The file object of the file involved in the I/O request.
Wait -
InputBuffer - Buffer which holds the inputs for the I/O request.
InputBufferLength - Length of the InputBuffer.
OutputBuffer - Where the results of the I/O request are placed.
OutputBufferLength - Length of the OutputBuffer.
IoControlCode - The controlcode describing the I/O to be done.
IoStatus - The results of the assignment.
DeviceObject - The device object which handles the I/O request.
Return Value:
TRUE - The I/O operation was handled and FALSE otherwise.
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PWEBDAV_DEVICE_OBJECT DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)DeviceObject;
PUMRX_DEVICE_OBJECT UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)DeviceObject;
LUID LocalServiceLogonID = LOCALSERVICE_LUID, ClientLogonID;
LUID SystemLogonID = SYSTEM_LUID;
BOOLEAN IsInLocalServiceProcess = FALSE, IsInSystemProcess = FALSE;
SECURITY_SUBJECT_CONTEXT ClientContext;
PAGED_CODE();
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Entering MRxDAVFastIoDeviceControl. IoControlCode = %08lx\n",
PsGetCurrentThreadId(), IoControlCode));
if (FileObject->FsContext != DavDeviceObject->CachedRxDeviceFcb) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFastIoDeviceControl: Wrong DeviceFcb!!\n",
PsGetCurrentThreadId()));
return FALSE;
}
SeCaptureSubjectContext( &(ClientContext) );
SeLockSubjectContext( &(ClientContext) );
NtStatus = SeQueryAuthenticationIdToken(SeQuerySubjectContextToken(&(ClientContext)),
&(ClientLogonID));
if (NtStatus == STATUS_SUCCESS) {
IsInLocalServiceProcess = RtlEqualLuid( &(ClientLogonID), &(LocalServiceLogonID) );
IsInSystemProcess = RtlEqualLuid( &(ClientLogonID), &(SystemLogonID) );
} else {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFastIoDeviceControl/SeQueryAuthenticationIdToken: "
"NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
}
SeUnlockSubjectContext( &(ClientContext) );
SeReleaseSubjectContext( &(ClientContext) );
//
// It's the right kind of fileobject. Go for it.
//
switch (IoControlCode) {
case IOCTL_UMRX_RELEASE_THREADS:
if (!IsInLocalServiceProcess && !IsInSystemProcess) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFastIoDeviceControl: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
PsGetCurrentThreadId()));
IoStatus->Status = STATUS_ACCESS_DENIED;
IoStatus->Information = 0;
return (FALSE);
}
UMRxReleaseCapturedThreads(UMRefDeviceObject);
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = 0;
return (TRUE);
case IOCTL_UMRX_GET_REQUEST:
case IOCTL_UMRX_RESPONSE_AND_REQUEST:
case IOCTL_UMRX_RESPONSE:
if (!IsInLocalServiceProcess && !IsInSystemProcess) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFastIoDeviceControl: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
PsGetCurrentThreadId()));
IoStatus->Status = STATUS_ACCESS_DENIED;
IoStatus->Information = 0;
return (FALSE);
}
UMRxAssignWork(UMRefDeviceObject,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
IoStatus);
return(TRUE);
case IOCTL_UMRX_GET_LOCK_OWNER:
//
// Validate the InputBuffer sent by the application.
//
try {
ProbeForRead(InputBuffer, InputBufferLength, sizeof(UCHAR));
} except (EXCEPTION_EXECUTE_HANDLER) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFastIoDeviceControl. STATUS_INVALID_USER_BUFFER(1)\n",
PsGetCurrentThreadId()));
IoStatus->Status = STATUS_INVALID_USER_BUFFER;
IoStatus->Information = 0;
return (FALSE);
}
//
// Validate the OutputBuffer sent by the application.
//
try {
ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(UCHAR));
} except (EXCEPTION_EXECUTE_HANDLER) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFastIoDeviceControl. STATUS_INVALID_USER_BUFFER(2)\n",
PsGetCurrentThreadId()));
IoStatus->Status = STATUS_INVALID_USER_BUFFER;
IoStatus->Information = 0;
return (FALSE);
}
MRxDAVGetLockOwnerFromFileName(DavDeviceObject,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
IoStatus);
return(TRUE);
default:
break;
}
//
// The I/O operation could not be handled.
//
return(FALSE);
}
NTSTATUS
MRxDAVFormatTheDAVContext(
PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
USHORT EntryPoint
)
/*++
Routine Description:
This routine formats the DAV Mini-Redir portion of the context.
Arguments:
AsyncEngineContext - The Reflector's context.
EntryPoint - The operation being performed.
Return Value:
none.
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PWEBDAV_CONTEXT DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
PRX_CONTEXT RxContext = AsyncEngineContext->RxContext;
PNT_CREATE_PARAMETERS NtCP = &(RxContext->Create.NtCreateParameters);
PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = NULL;
PMRX_SRV_CALL SrvCall = NULL;
PWEBDAV_SRV_CALL DavSrvCall = NULL;
PMRX_V_NET_ROOT VNetRoot = NULL;
PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
PSECURITY_CLIENT_CONTEXT SecClnCtx = NULL;
BOOL AlreadyInitialized = FALSE, SecurityClientContextCreated = FALSE;
SECURITY_QUALITY_OF_SERVICE SecurityQos;
PSECURITY_SUBJECT_CONTEXT SecSubCtx = NULL;
PSECURITY_QUALITY_OF_SERVICE SecQOS = NULL;
PAGED_CODE();
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Entering MRxDAVFormatTheDAVContext!!!!\n",
PsGetCurrentThreadId()));
DavDbgTrace(DAV_TRACE_CONTEXT,
("%ld: MRxDAVFormatTheDAVContext: AsyncEngineContext: %08lx, "
"EntryPoint: %d.\n", PsGetCurrentThreadId(),
AsyncEngineContext, EntryPoint));
ASSERT(DavContext != NULL);
ASSERT(RxContext != NULL);
//
// Set the EntryPoint field. If this is not a Create operation, we can
// return.
//
DavContext->EntryPoint = EntryPoint;
if (EntryPoint != DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL &&
EntryPoint != DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT) {
return NtStatus;
}
//
// Since this is a create call, get the client's security context. This is
// used to impersonate the client before sending the requests to the server.
//
if ( NtCP->SecurityContext != NULL &&
NtCP->SecurityContext->AccessState != NULL ) {
//
// Check whether its a CreateSrvCall call or a CreateVNetRoot call.
//
if ( EntryPoint != DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL ) {
//
// This is s CreateVNetRoot call.
//
ASSERT(EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT);
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVFormatTheDAVContext. CreateVNetRoot.\n",
PsGetCurrentThreadId()));
//
// The VNetRoot pointer is stored in the MRxContext[1] pointer of the
// RxContext structure. This is done in the MRxDAVCreateVNetRoot function.
//
VNetRoot = RxContext->MRxContext[1];
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVFormatTheDAVContext. VNetRoot = %08lx\n",
PsGetCurrentThreadId(), VNetRoot));
//
// The context pointer of the V_NET_ROOT already points to a blob of
// memory, the size of which is sizeof(WEBDAV_V_NET_ROOT). This
// should never be NULL.
//
DavVNetRoot = MRxDAVGetVNetRootExtension(VNetRoot);
if(DavVNetRoot == NULL) {
ASSERT(FALSE);
goto EXIT_THE_FUNCTION;
}
SecClnCtx = &(DavVNetRoot->SecurityClientContext);
//
// Only need to initialize on the first create call by the user.
//
if (DavVNetRoot->SCAlreadyInitialized) {
AlreadyInitialized = TRUE;
}
} else {
//
// This is a CreateSrvCall call.
//
ASSERT(EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL);
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVFormatTheDAVContext. CreateSrvCall.\n",
PsGetCurrentThreadId()));
//
// The SrvCall pointer is stored in the SCCBC structure which is
// stored in the MRxContext[1] pointer of the RxContext structure.
// This is done in the MRxDAVCreateSrvCall function.
//
ASSERT(RxContext->MRxContext[1] != NULL);
SCCBC = (PMRX_SRVCALL_CALLBACK_CONTEXT)RxContext->MRxContext[1];
SrvCall = SCCBC->SrvCalldownStructure->SrvCall;
ASSERT(SrvCall != NULL);
DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
ASSERT(DavSrvCall != NULL);
//
// At this time, we don't have a V_NET_ROOT and hence cannot store
// the SecurityClientContext. We just use MRxContext[2] of RxContext
// to pass the SecurityClientContext.
//
SecClnCtx = RxAllocatePoolWithTag(NonPagedPool,
sizeof(SECURITY_CLIENT_CONTEXT),
DAV_SRVCALL_POOLTAG);
if (SecClnCtx == NULL) {
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFormatTheDAVContext/RxAllocatePoolWithTag.\n",
PsGetCurrentThreadId()));
goto EXIT_THE_FUNCTION;
}
ASSERT(RxContext->MRxContext[2] == NULL);
RxContext->MRxContext[2] = (PVOID)SecClnCtx;
}
if (!AlreadyInitialized) {
SecSubCtx = &(NtCP->SecurityContext->AccessState->SubjectSecurityContext);
SecQOS = ( (NtCP->SecurityContext->SecurityQos) ?
(NtCP->SecurityContext->SecurityQos) : &(SecurityQos) );
//
// If the user did not specify the security QOS structure, create
// one. We set the value of SecurityQos.EffectiveOnly to FALSE
// to keep the privilege so that we can do certain operations
// later on. This is specifically needed for the EFS operations.
// If set to TRUE, any privilege not enabled at this time will be
// lost. In the EFS case, the "restore" privilege is lost.
//
if (NtCP->SecurityContext->SecurityQos == NULL) {
SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQos.ImpersonationLevel = DEFAULT_IMPERSONATION_LEVEL;
SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQos.EffectiveOnly = FALSE;
}
//
// This call sets the SecurityClientContext of the user. This is
// stored in the V_NET_ROOT since its a per user thing. This
// strucutre is used later on in impersonating the client that
// issued the I/O request.
//
NtStatus = SeCreateClientSecurityFromSubjectContext(SecSubCtx,
SecQOS,
// Srv Remote ?
FALSE,
SecClnCtx);
//
// If unsuccessful, return NULL.
//
if (NtStatus != STATUS_SUCCESS) {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFormatTheDAVContext/"
"SeCreateClientSecurityFromSubjectContext. Error "
"Val = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
goto EXIT_THE_FUNCTION;
}
SecurityClientContextCreated = TRUE;
//
// If this was a create call, set the bool in the DavVNetRoot to
// indicate that the SecurityClientContext has been initialized.
//
if (EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT) {
DavVNetRoot->SCAlreadyInitialized = TRUE;
} else{
ASSERT(EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL);
DavSrvCall->SCAlreadyInitialized = TRUE;
}
}
} else {
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVFormatTheDAVContext. Could not get SecClnCtx."
"EntryPoint = %d.\n", PsGetCurrentThreadId(), EntryPoint));
}
EXIT_THE_FUNCTION:
if (NtStatus != STATUS_SUCCESS) {
if (EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL && SecClnCtx != NULL) {
if (SecurityClientContextCreated) {
SeDeleteClientSecurity(SecClnCtx);
DavSrvCall->SCAlreadyInitialized = FALSE;
}
RxFreePool(SecClnCtx);
RxContext->MRxContext[2] = NULL;
}
}
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: Leaving MRxDAVFormatTheDAVContext with NtStatus = %08lx.\n",
PsGetCurrentThreadId(), NtStatus));
return NtStatus;
}
NTSTATUS
MRxDavDeleteConnection(
IN OUT PRX_CONTEXT RxContext
)
/*++
Routine Description:
This routine deletes a VNetroot. The result depends on the forcelevel. If called
with maximum force, this will delete all connections and orphan the fileobjects
working on files for this VNetRoot.
Arguments:
RxContext - the RDBSS context
Return Value:
RXSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
RxCaptureFobx;
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
PLMR_REQUEST_PACKET InputBuffer = LowIoContext->ParamsFor.FsCtl.pInputBuffer;
ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
ULONG Level;
PMRX_V_NET_ROOT VNetRoot;
PMRX_NET_ROOT NetRoot;
PAGED_CODE();
#if 0
if (!Wait) {
//just post right now!
*PostToFsp = TRUE;
return(STATUS_PENDING);
}
#endif
try {
if (NodeType(capFobx)==RDBSS_NTC_V_NETROOT) {
VNetRoot = (PMRX_V_NET_ROOT)capFobx;
NetRoot = (PMRX_NET_ROOT)VNetRoot->pNetRoot;
} else {
ASSERT(FALSE);
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
}
if (InputBufferLength < sizeof(DWORD)) {
try_return(Status = STATUS_BUFFER_TOO_SMALL);
}
Level = *((DWORD *)InputBuffer);
if (Level <= USE_LOTS_OF_FORCE) {
if (VNetRoot != NULL && Level == USE_LOTS_OF_FORCE) {
}
Status = RxFinalizeConnection(
(PNET_ROOT)NetRoot,
(PV_NET_ROOT)VNetRoot,
(BOOLEAN)(Level == USE_LOTS_OF_FORCE));
} else {
Status = STATUS_INVALID_PARAMETER;
}
try_return(Status);
try_exit:NOTHING;
} finally {
#if 0
if (TableLockHeld) {
RxReleasePrefixTableLock( &RxNetNameTable );
}
#endif
}
return Status;
}
VOID
MRxDAVGetLockOwnerFromFileName(
IN PWEBDAV_DEVICE_OBJECT MRxDAVDeviceObject,
IN OUT PWCHAR InputBuffer,
IN ULONG InputBufferLength,
OUT PWCHAR OutputBuffer,
IN ULONG OutputBufferLength,
OUT PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
This routine goes through the global LockConflictEntryList and deletes
all the expired entries. It then looks at the entry whose CompletePathName
matches the FileName of the InputBuffer and fills in the LockOwner of
that entry in the OutputBuffer.
Arguments:
MRxDAVDeviceObject - The WebDav deviceobject that is in play.
InputBuffer - The Input buffer that came down from the user mode. This
contains the CompletePathName of the file in question.
InputBufferLength - Length of the InputBuffer.
OutputBuffer - The Output buffer that came down from the user mode. The
LockOwner (if one is found) is filled here.
OutputBufferLength - Length of the OutputBuffer.
IoStatus - The results of the assignment.
Return Value:
None.
--*/
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PLIST_ENTRY ConflictListEntry = NULL;
PWEBDAV_LOCK_CONFLICT_ENTRY LockConflictEntry = NULL;
BOOL lockAcquired = FALSE, entryFound = FALSE;
//
// Note: InputBuffer and OutputBuffer may point to the same address since
// this IOCTL is METHOD_BUFFERED, and we could have enterd it via the IRP
// path instead of Fast I/O path.
//
//
// We need to disable APCs on this thread now.
//
FsRtlEnterFileSystem();
//
// First, go through the list and free up all the old entries. We supply
// FALSE since we only want to cleanup the expired entries.
//
MRxDAVCleanUpTheLockConflictList(FALSE);
//
// Now that we have cleaned up all the old entries, go through the list
// and find out the entry that matches the PathName. Fill the OutputBuffer
// with the LockOwner string.
//
ExAcquireResourceExclusiveLite(&(LockConflictEntryListLock), TRUE);
lockAcquired = TRUE;
ConflictListEntry = LockConflictEntryList.Flink;
while ( ConflictListEntry != &(LockConflictEntryList) ) {
//
// Get the pointer to the WEBDAV_LOCK_CONFLICT_ENTRY structure.
//
LockConflictEntry = CONTAINING_RECORD(ConflictListEntry,
WEBDAV_LOCK_CONFLICT_ENTRY,
listEntry);
ConflictListEntry = ConflictListEntry->Flink;
//
// If the SizeInBytes of the LockConflictEntry->CompletePathName is
// greater than the InputBufferLength, then we continue.
//
if ( ((1 + wcslen(LockConflictEntry->CompletePathName)) * sizeof(WCHAR)) > InputBufferLength ) {
continue;
}
try {
//
// If the CompletePathName exactly matches the InputBuffer string
// that was passed then this is the LockConflictEntry we are
// interested in.
//
if ( !_wcsnicmp(LockConflictEntry->CompletePathName, InputBuffer, wcslen(LockConflictEntry->CompletePathName)) ) {
if ( InputBuffer[wcslen(LockConflictEntry->CompletePathName)] == L'\0' ) {
entryFound = TRUE;
break;
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
NtStatus = STATUS_INVALID_USER_BUFFER;
goto EXIT_THE_FUNCTION;
}
}
if (entryFound) {
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVGetLockOwnerFromFileName. entryFound == TRUE\n",
PsGetCurrentThreadId()));
//
// We need to make sure that the OutputBuffer is large enough to hold
// the LockOwner string.
//
if ( OutputBufferLength < ((1 + wcslen(LockConflictEntry->LockOwner)) * sizeof(WCHAR)) ) {
NtStatus = STATUS_BUFFER_TOO_SMALL;
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVGetLockOwnerFromFileName. STATUS_BUFFER_TOO_SMALL\n",
PsGetCurrentThreadId()));
goto EXIT_THE_FUNCTION;
}
try {
wcsncpy(OutputBuffer, LockConflictEntry->LockOwner, wcslen(LockConflictEntry->LockOwner));
OutputBuffer[wcslen(LockConflictEntry->LockOwner)] = L'\0';
} except (EXCEPTION_EXECUTE_HANDLER) {
NtStatus = STATUS_INVALID_USER_BUFFER;
DavDbgTrace(DAV_TRACE_ERROR,
("%ld: ERROR: MRxDAVGetLockOwnerFromFileName. STATUS_INVALID_USER_BUFFER(3)\n",
PsGetCurrentThreadId()));
goto EXIT_THE_FUNCTION;
}
NtStatus = STATUS_SUCCESS;
} else {
DavDbgTrace(DAV_TRACE_DETAIL,
("%ld: MRxDAVGetLockOwnerFromFileName. entryFound == FALSE\n",
PsGetCurrentThreadId()));
NtStatus = STATUS_NO_SUCH_FILE;
}
EXIT_THE_FUNCTION:
IoStatus->Status = NtStatus;
//
// If NtStatus is STATUS_BUFFER_TOO_SMALL, we need to return the size
// needed to hold the LoackOwner name.
//
if (NtStatus == STATUS_SUCCESS || NtStatus == STATUS_BUFFER_TOO_SMALL) {
IoStatus->Information = ( (1 + wcslen(LockConflictEntry->LockOwner)) * sizeof(WCHAR) );
} else {
IoStatus->Information = 0;
}
if (lockAcquired) {
ExReleaseResourceLite(&(LockConflictEntryListLock));
lockAcquired = FALSE;
}
FsRtlExitFileSystem();
return;
}
VOID
MRxDAVCleanUpTheLockConflictList(
BOOL CleanUpAllEntries
)
/*++
Routine Description:
This routine goes through the global LockConflictEntryList and deletes
all the expired entries or all the entries depending upon the value of
CleanUpAllEntries.
Arguments:
CleanUpAllEntries - If TRUE, it cleans up all the entries.
If FALSE, it cleans up only the expired items.
Return Value:
None.
--*/
{
PLIST_ENTRY ConflictListEntry = NULL;
PWEBDAV_LOCK_CONFLICT_ENTRY LockConflictEntry = NULL;
LARGE_INTEGER CurrentSystemTickCount, TickCountDifference;
LARGE_INTEGER EntryTimeoutValueInTickCount;
//
// Go through the list and free up all the old entries. Acquire the LOCK
// first.
//
ExAcquireResourceExclusiveLite(&(LockConflictEntryListLock), TRUE);
ConflictListEntry = LockConflictEntryList.Flink;
while ( ConflictListEntry != &(LockConflictEntryList) ) {
//
// Get the pointer to the WEBDAV_LOCK_CONFLICT_ENTRY structure.
//
LockConflictEntry = CONTAINING_RECORD(ConflictListEntry,
WEBDAV_LOCK_CONFLICT_ENTRY,
listEntry);
ConflictListEntry = ConflictListEntry->Flink;
//
// 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 WEBDAV_LOCKCONFLICTENTRY_LIFETIMEINSEC.
//
EntryTimeoutValueInTickCount.QuadPart = ( (1000 * 1000 * 10) / KeQueryTimeIncrement() );
EntryTimeoutValueInTickCount.QuadPart *= WEBDAV_LOCKCONFLICTENTRY_LIFETIMEINSEC;
KeQueryTickCount( &(CurrentSystemTickCount) );
//
// Get the time elapsed (in system tick counts) since the time this
// LockConflictEntry was created.
//
TickCountDifference.QuadPart = (CurrentSystemTickCount.QuadPart - LockConflictEntry->CreationTimeInTickCount.QuadPart);
//
// If the TickCountDifference is greater than EntryTimeoutValueInTickCount
// we need to remove this this entry from the list and free it. If
// CleanUpAllEntries is TRUE, we free it whether its expired or not.
//
if ( (CleanUpAllEntries) ||
(TickCountDifference.QuadPart > EntryTimeoutValueInTickCount.QuadPart) ) {
RemoveEntryList( &(LockConflictEntry->listEntry) );
RxFreePool(LockConflictEntry->CompletePathName);
LockConflictEntry->CompletePathName = NULL;
RxFreePool(LockConflictEntry->LockOwner);
LockConflictEntry->LockOwner = NULL;
RxFreePool(LockConflictEntry);
LockConflictEntry = NULL;
}
}
ExReleaseResourceLite(&(LockConflictEntryListLock));
return;
}