reactos/drivers/filesystems/udfs/misc.cpp

2595 lines
88 KiB
C++

////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////
/*
File: Misc.cpp
Module: UDF File System Driver (Kernel mode execution only)
Description:
This file contains some miscellaneous support routines.
*/
#include "udffs.h"
// define the file specific bug-check id
#define UDF_BUG_CHECK_ID UDF_FILE_MISC
#include <stdio.h>
//CCHAR DefLetter[] = {""};
/*
Function: UDFInitializeZones()
Description:
Allocates some memory for global zones used to allocate FSD structures.
Either all memory will be allocated or we will back out gracefully.
Expected Interrupt Level (for execution) :
IRQL_PASSIVE_LEVEL
Return Value: STATUS_SUCCESS/Error
*/
NTSTATUS
UDFInitializeZones(VOID)
{
NTSTATUS RC = STATUS_SUCCESS;
uint32 SizeOfZone = UDFGlobalData.DefaultZoneSizeInNumStructs;
uint32 SizeOfObjectNameZone = 0;
uint32 SizeOfCCBZone = 0;
// uint32 SizeOfFCBZone = 0;
uint32 SizeOfIrpContextZone = 0;
// uint32 SizeOfFileInfoZone = 0;
_SEH2_TRY {
// initialize the spinlock protecting the zones
KeInitializeSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock));
// determine memory requirements
switch (MmQuerySystemSize()) {
case MmMediumSystem:
SizeOfObjectNameZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
SizeOfCCBZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER);
SizeOfIrpContextZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
UDFGlobalData.MaxDelayedCloseCount = 24;
UDFGlobalData.MinDelayedCloseCount = 6;
UDFGlobalData.MaxDirDelayedCloseCount = 8;
UDFGlobalData.MinDirDelayedCloseCount = 2;
UDFGlobalData.WCacheMaxFrames = 8*4;
UDFGlobalData.WCacheMaxBlocks = 16*64;
UDFGlobalData.WCacheBlocksPerFrameSh = 8;
UDFGlobalData.WCacheFramesToKeepFree = 4;
break;
case MmLargeSystem:
SizeOfObjectNameZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
SizeOfCCBZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER);
SizeOfIrpContextZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
UDFGlobalData.MaxDelayedCloseCount = 72;
UDFGlobalData.MinDelayedCloseCount = 18;
UDFGlobalData.MaxDirDelayedCloseCount = 24;
UDFGlobalData.MinDirDelayedCloseCount = 6;
UDFGlobalData.WCacheMaxFrames = 2*16*4;
UDFGlobalData.WCacheMaxBlocks = 2*16*64;
UDFGlobalData.WCacheBlocksPerFrameSh = 8;
UDFGlobalData.WCacheFramesToKeepFree = 8;
break;
case MmSmallSystem:
default:
SizeOfObjectNameZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
SizeOfCCBZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER);
SizeOfIrpContextZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
UDFGlobalData.MaxDelayedCloseCount = 8;
UDFGlobalData.MinDelayedCloseCount = 2;
UDFGlobalData.MaxDirDelayedCloseCount = 6;
UDFGlobalData.MinDirDelayedCloseCount = 1;
UDFGlobalData.WCacheMaxFrames = 8*4/2;
UDFGlobalData.WCacheMaxBlocks = 16*64/2;
UDFGlobalData.WCacheBlocksPerFrameSh = 8;
UDFGlobalData.WCacheFramesToKeepFree = 2;
}
// typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-)
if (MmIsThisAnNtAsSystem()) {
SizeOfObjectNameZone *= UDF_NTAS_MULTIPLE;
SizeOfCCBZone *= UDF_NTAS_MULTIPLE;
SizeOfIrpContextZone *= UDF_NTAS_MULTIPLE;
}
// allocate memory for each of the zones and initialize the zones ...
if (!(UDFGlobalData.ObjectNameZone = DbgAllocatePool(NonPagedPool, SizeOfObjectNameZone))) {
RC = STATUS_INSUFFICIENT_RESOURCES;
try_return(RC);
}
if (!(UDFGlobalData.CCBZone = DbgAllocatePool(NonPagedPool, SizeOfCCBZone))) {
RC = STATUS_INSUFFICIENT_RESOURCES;
try_return(RC);
}
if (!(UDFGlobalData.IrpContextZone = DbgAllocatePool(NonPagedPool, SizeOfIrpContextZone))) {
RC = STATUS_INSUFFICIENT_RESOURCES;
try_return(RC);
}
// initialize each of the zone headers ...
if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.ObjectNameZoneHeader),
UDFQuadAlign(sizeof(UDFObjectName)),
UDFGlobalData.ObjectNameZone, SizeOfObjectNameZone))) {
// failed the initialization, leave ...
try_return(RC);
}
if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.CCBZoneHeader),
UDFQuadAlign(sizeof(UDFCCB)),
UDFGlobalData.CCBZone,
SizeOfCCBZone))) {
// failed the initialization, leave ...
try_return(RC);
}
if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.IrpContextZoneHeader),
UDFQuadAlign(sizeof(UDFIrpContext)),
UDFGlobalData.IrpContextZone,
SizeOfIrpContextZone))) {
// failed the initialization, leave ...
try_return(RC);
}
try_exit: NOTHING;
} _SEH2_FINALLY {
if (!NT_SUCCESS(RC)) {
// invoke the destroy routine now ...
UDFDestroyZones();
} else {
// mark the fact that we have allocated zones ...
UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_ZONES_INITIALIZED);
}
} _SEH2_END;
return(RC);
}
/*************************************************************************
*
* Function: UDFDestroyZones()
*
* Description:
* Free up the previously allocated memory. NEVER do this once the
* driver has been successfully loaded.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
VOID UDFDestroyZones(VOID)
{
// BrutePoint();
_SEH2_TRY {
// free up each of the pools
if(UDFGlobalData.ObjectNameZone) {
DbgFreePool(UDFGlobalData.ObjectNameZone);
UDFGlobalData.ObjectNameZone = NULL;
}
if(UDFGlobalData.CCBZone) {
DbgFreePool(UDFGlobalData.CCBZone);
UDFGlobalData.CCBZone = NULL;
}
if(UDFGlobalData.IrpContextZone) {
DbgFreePool(UDFGlobalData.IrpContextZone);
UDFGlobalData.IrpContextZone = NULL;
}
//try_exit: NOTHING;
} _SEH2_FINALLY {
UDFGlobalData.UDFFlags &= ~UDF_DATA_FLAGS_ZONES_INITIALIZED;
} _SEH2_END;
return;
}
/*************************************************************************
*
* Function: UDFIsIrpTopLevel()
*
* Description:
* Helps the FSD determine who the "top level" caller is for this
* request. A request can originate directly from a user process
* (in which case, the "top level" will be NULL when this routine
* is invoked), OR the user may have originated either from the NT
* Cache Manager/VMM ("top level" may be set), or this could be a
* recursion into our code in which we would have set the "top level"
* field the last time around.
*
* Expected Interrupt Level (for execution) :
*
* whatever level a particular dispatch routine is invoked at.
*
* Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked)
*
*************************************************************************/
BOOLEAN
__fastcall
UDFIsIrpTopLevel(
PIRP Irp) // the IRP sent to our dispatch routine
{
if(!IoGetTopLevelIrp()) {
// OK, so we can set ourselves to become the "top level" component
IoSetTopLevelIrp(Irp);
return TRUE;
}
return FALSE;
}
/*************************************************************************
*
* Function: UDFExceptionFilter()
*
* Description:
* This routines allows the driver to determine whether the exception
* is an "allowed" exception i.e. one we should not-so-quietly consume
* ourselves, or one which should be propagated onwards in which case
* we will most likely bring down the machine.
*
* This routine employs the services of FsRtlIsNtstatusExpected(). This
* routine returns a BOOLEAN result. A RC of FALSE will cause us to return
* EXCEPTION_CONTINUE_SEARCH which will probably cause a panic.
* The FsRtl.. routine returns FALSE iff exception values are (currently) :
* STATUS_DATATYPE_MISALIGNMENT || STATUS_ACCESS_VIOLATION ||
* STATUS_ILLEGAL_INSTRUCTION || STATUS_INSTRUCTION_MISALIGNMENT
*
* Expected Interrupt Level (for execution) :
*
* ?
*
* Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH
*
*************************************************************************/
long
UDFExceptionFilter(
PtrUDFIrpContext PtrIrpContext,
PEXCEPTION_POINTERS PtrExceptionPointers
)
{
long ReturnCode = EXCEPTION_EXECUTE_HANDLER;
NTSTATUS ExceptionCode = STATUS_SUCCESS;
#if defined UDF_DBG || defined PRINT_ALWAYS
ULONG i;
UDFPrint(("UDFExceptionFilter\n"));
UDFPrint((" Ex. Code: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionCode));
UDFPrint((" Ex. Addr: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionAddress));
UDFPrint((" Ex. Flag: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionFlags));
UDFPrint((" Ex. Pnum: %x\n",PtrExceptionPointers->ExceptionRecord->NumberParameters));
for(i=0;i<PtrExceptionPointers->ExceptionRecord->NumberParameters;i++) {
UDFPrint((" %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionInformation[i]));
}
#ifdef _X86_
UDFPrint(("Exception context:\n"));
if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_INTEGER) {
UDFPrint(("EAX=%8.8x ",PtrExceptionPointers->ContextRecord->Eax));
UDFPrint(("EBX=%8.8x ",PtrExceptionPointers->ContextRecord->Ebx));
UDFPrint(("ECX=%8.8x ",PtrExceptionPointers->ContextRecord->Ecx));
UDFPrint(("EDX=%8.8x\n",PtrExceptionPointers->ContextRecord->Edx));
UDFPrint(("ESI=%8.8x ",PtrExceptionPointers->ContextRecord->Esi));
UDFPrint(("EDI=%8.8x ",PtrExceptionPointers->ContextRecord->Edi));
}
if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_CONTROL) {
UDFPrint(("EBP=%8.8x ",PtrExceptionPointers->ContextRecord->Esp));
UDFPrint(("ESP=%8.8x\n",PtrExceptionPointers->ContextRecord->Ebp));
UDFPrint(("EIP=%8.8x\n",PtrExceptionPointers->ContextRecord->Eip));
}
// UDFPrint(("Flags: %s %s ",PtrExceptionPointers->ContextRecord->Eip));
#endif //_X86_
#endif // UDF_DBG
// figure out the exception code
ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode;
if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) {
ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2];
}
if (PtrIrpContext) {
PtrIrpContext->SavedExceptionCode = ExceptionCode;
UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_EXCEPTION);
}
// check if we should propagate this exception or not
if (!(FsRtlIsNtstatusExpected(ExceptionCode))) {
// better free up the IrpContext now ...
if (PtrIrpContext) {
UDFPrint((" UDF Driver internal error\n"));
BrutePoint();
} else {
// we are not ok, propagate this exception.
// NOTE: we will bring down the machine ...
ReturnCode = EXCEPTION_CONTINUE_SEARCH;
}
}
// return the appropriate code
return(ReturnCode);
} // end UDFExceptionFilter()
/*************************************************************************
*
* Function: UDFExceptionHandler()
*
* Description:
* One of the routines in the FSD or in the modules we invoked encountered
* an exception. We have decided that we will "handle" the exception.
* Therefore we will prevent the machine from a panic ...
* You can do pretty much anything you choose to in your commercial
* driver at this point to ensure a graceful exit. In the UDF
* driver, We shall simply free up the IrpContext (if any), set the
* error code in the IRP and complete the IRP at this time ...
*
* Expected Interrupt Level (for execution) :
*
* ?
*
* Return Value: Error code
*
*************************************************************************/
NTSTATUS
UDFExceptionHandler(
PtrUDFIrpContext PtrIrpContext,
PIRP Irp
)
{
// NTSTATUS RC;
NTSTATUS ExceptionCode = STATUS_INSUFFICIENT_RESOURCES;
PDEVICE_OBJECT Device;
PVPB Vpb;
PETHREAD Thread;
UDFPrint(("UDFExceptionHandler \n"));
// ASSERT(Irp);
if (!Irp) {
UDFPrint((" !Irp, return\n"));
ASSERT(!PtrIrpContext);
return ExceptionCode;
}
// If it was a queued close (or something like this) then we need not
// completing it because of MUST_SUCCEED requirement.
if (PtrIrpContext) {
ExceptionCode = PtrIrpContext->SavedExceptionCode;
// Free irp context here
// UDFReleaseIrpContext(PtrIrpContext);
} else {
UDFPrint((" complete Irp and return\n"));
// must be insufficient resources ...?
ExceptionCode = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = ExceptionCode;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ExceptionCode;
}
// Check if we are posting this request. One of the following must be true
// if we are to post a request.
//
// - Status code is STATUS_CANT_WAIT and the request is asynchronous
// or we are forcing this to be posted.
//
// - Status code is STATUS_VERIFY_REQUIRED and we are at APC level
// or higher. Can't wait for IO in the verify path in this case.
//
// Set the MORE_PROCESSING flag in the IrpContext to keep if from being
// deleted if this is a retryable condition.
if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
if (KeGetCurrentIrql() >= APC_LEVEL) {
UDFPrint((" use UDFPostRequest()\n"));
ExceptionCode = UDFPostRequest( PtrIrpContext, Irp );
}
}
// If we posted the request or our caller will retry then just return here.
if ((ExceptionCode == STATUS_PENDING) ||
(ExceptionCode == STATUS_CANT_WAIT)) {
UDFPrint((" STATUS_PENDING/STATUS_CANT_WAIT, return\n"));
return ExceptionCode;
}
// Store this error into the Irp for posting back to the Io system.
Irp->IoStatus.Status = ExceptionCode;
if (IoIsErrorUserInduced( ExceptionCode )) {
// Check for the various error conditions that can be caused by,
// and possibly resolved my the user.
if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
// Now we are at the top level file system entry point.
//
// If we have already posted this request then the device to
// verify is in the original thread. Find this via the Irp.
Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
// If there is no device in that location then check in the
// current thread.
if (Device == NULL) {
Device = IoGetDeviceToVerify( PsGetCurrentThread() );
IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
ASSERT( Device != NULL );
// Let's not BugCheck just because the driver screwed up.
if (Device == NULL) {
UDFPrint((" Device == NULL, return\n"));
ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
Irp->IoStatus.Status = ExceptionCode;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_NO_INCREMENT);
UDFReleaseIrpContext(PtrIrpContext);
return ExceptionCode;
}
}
UDFPrint((" use UDFPerformVerify()\n"));
// UDFPerformVerify() will do the right thing with the Irp.
// If we return STATUS_CANT_WAIT then the current thread
// can retry the request.
return UDFPerformVerify( PtrIrpContext, Irp, Device );
}
//
// The other user induced conditions generate an error unless
// they have been disabled for this request.
//
if (FlagOn( PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS )) {
UDFPrint((" DISABLE_POPUPS, complete Irp and return\n"));
Irp->IoStatus.Status = ExceptionCode;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_NO_INCREMENT);
UDFReleaseIrpContext(PtrIrpContext);
return ExceptionCode;
} else {
// Generate a pop-up
if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) {
Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb;
} else {
Vpb = NULL;
}
// The device to verify is either in my thread local storage
// or that of the thread that owns the Irp.
Thread = Irp->Tail.Overlay.Thread;
Device = IoGetDeviceToVerify( Thread );
if (Device == NULL) {
Thread = PsGetCurrentThread();
Device = IoGetDeviceToVerify( Thread );
ASSERT( Device != NULL );
// Let's not BugCheck just because the driver screwed up.
if (Device == NULL) {
UDFPrint((" Device == NULL, return(2)\n"));
Irp->IoStatus.Status = ExceptionCode;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_NO_INCREMENT);
UDFReleaseIrpContext(PtrIrpContext);
return ExceptionCode;
}
}
// This routine actually causes the pop-up. It usually
// does this by queuing an APC to the callers thread,
// but in some cases it will complete the request immediately,
// so it is very important to IoMarkIrpPending() first.
IoMarkIrpPending( Irp );
IoRaiseHardError( Irp, Vpb, Device );
// We will be handing control back to the caller here, so
// reset the saved device object.
UDFPrint((" use IoSetDeviceToVerify()\n"));
IoSetDeviceToVerify( Thread, NULL );
// The Irp will be completed by Io or resubmitted. In either
// case we must clean up the IrpContext here.
UDFReleaseIrpContext(PtrIrpContext);
return STATUS_PENDING;
}
}
// If it was a normal request from IOManager then complete it
if (Irp) {
UDFPrint((" complete Irp\n"));
// set the error code in the IRP
Irp->IoStatus.Status = ExceptionCode;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_NO_INCREMENT);
UDFReleaseIrpContext(PtrIrpContext);
}
UDFPrint((" return from exception handler with code %x\n", ExceptionCode));
return(ExceptionCode);
} // end UDFExceptionHandler()
/*************************************************************************
*
* Function: UDFLogEvent()
*
* Description:
* Log a message in the NT Event Log. This is a rather simplistic log
* methodology since we can potentially utilize the event log to
* provide a lot of information to the user (and you should too!)
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
VOID
UDFLogEvent(
NTSTATUS UDFEventLogId, // the UDF private message id
NTSTATUS RC) // any NT error code we wish to log ...
{
_SEH2_TRY {
// Implement a call to IoAllocateErrorLogEntry() followed by a call
// to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry()
// will free memory for the entry once the write completes (which in actuality
// is an asynchronous operation).
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
// nothing really we can do here, just do not wish to crash ...
NOTHING;
} _SEH2_END;
return;
} // end UDFLogEvent()
/*************************************************************************
*
* Function: UDFAllocateObjectName()
*
* Description:
* Allocate a new ObjectName structure to represent an open on-disk object.
* Also initialize the ObjectName structure to NULL.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: A pointer to the ObjectName structure OR NULL.
*
*************************************************************************/
PtrUDFObjectName
UDFAllocateObjectName(VOID)
{
PtrUDFObjectName PtrObjectName = NULL;
BOOLEAN AllocatedFromZone = TRUE;
KIRQL CurrentIrql;
// first, __try to allocate out of the zone
KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
if (!ExIsFullZone(&(UDFGlobalData.ObjectNameZoneHeader))) {
// we have enough memory
PtrObjectName = (PtrUDFObjectName)ExAllocateFromZone(&(UDFGlobalData.ObjectNameZoneHeader));
// release the spinlock
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
} else {
// release the spinlock
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
// if we failed to obtain from the zone, get it directly from the VMM
PtrObjectName = (PtrUDFObjectName)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFObjectName)));
AllocatedFromZone = FALSE;
}
if (!PtrObjectName) {
return NULL;
}
// zero out the allocated memory block
RtlZeroMemory(PtrObjectName, UDFQuadAlign(sizeof(UDFObjectName)));
// set up some fields ...
PtrObjectName->NodeIdentifier.NodeType = UDF_NODE_TYPE_OBJECT_NAME;
PtrObjectName->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFObjectName));
if (!AllocatedFromZone) {
UDFSetFlag(PtrObjectName->ObjectNameFlags, UDF_OBJ_NAME_NOT_FROM_ZONE);
}
return(PtrObjectName);
} // end UDFAllocateObjectName()
/*************************************************************************
*
* Function: UDFReleaseObjectName()
*
* Description:
* Deallocate a previously allocated structure.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
VOID
__fastcall
UDFReleaseObjectName(
PtrUDFObjectName PtrObjectName)
{
KIRQL CurrentIrql;
ASSERT(PtrObjectName);
// give back memory either to the zone or to the VMM
if (!(PtrObjectName->ObjectNameFlags & UDF_OBJ_NAME_NOT_FROM_ZONE)) {
// back to the zone
KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
ExFreeToZone(&(UDFGlobalData.ObjectNameZoneHeader), PtrObjectName);
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
} else {
MyFreePool__(PtrObjectName);
}
return;
} // end UDFReleaseObjectName()
/*************************************************************************
*
* Function: UDFAllocateCCB()
*
* Description:
* Allocate a new CCB structure to represent an open on-disk object.
* Also initialize the CCB structure to NULL.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: A pointer to the CCB structure OR NULL.
*
*************************************************************************/
PtrUDFCCB
UDFAllocateCCB(VOID)
{
PtrUDFCCB Ccb = NULL;
BOOLEAN AllocatedFromZone = TRUE;
KIRQL CurrentIrql;
// first, __try to allocate out of the zone
KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
if (!ExIsFullZone(&(UDFGlobalData.CCBZoneHeader))) {
// we have enough memory
Ccb = (PtrUDFCCB)ExAllocateFromZone(&(UDFGlobalData.CCBZoneHeader));
// release the spinlock
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
} else {
// release the spinlock
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
// if we failed to obtain from the zone, get it directly from the VMM
Ccb = (PtrUDFCCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFCCB)));
AllocatedFromZone = FALSE;
// UDFPrint((" CCB allocated @%x\n",Ccb));
}
if (!Ccb) {
return NULL;
}
// zero out the allocated memory block
RtlZeroMemory(Ccb, UDFQuadAlign(sizeof(UDFCCB)));
// set up some fields ...
Ccb->NodeIdentifier.NodeType = UDF_NODE_TYPE_CCB;
Ccb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFCCB));
if (!AllocatedFromZone) {
UDFSetFlag(Ccb->CCBFlags, UDF_CCB_NOT_FROM_ZONE);
}
UDFPrint(("UDFAllocateCCB: %x\n", Ccb));
return(Ccb);
} // end UDFAllocateCCB()
/*************************************************************************
*
* Function: UDFReleaseCCB()
*
* Description:
* Deallocate a previously allocated structure.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
VOID
__fastcall
UDFReleaseCCB(
PtrUDFCCB Ccb
)
{
KIRQL CurrentIrql;
ASSERT(Ccb);
UDFPrint(("UDFReleaseCCB: %x\n", Ccb));
// give back memory either to the zone or to the VMM
if(!(Ccb->CCBFlags & UDF_CCB_NOT_FROM_ZONE)) {
// back to the zone
KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
ExFreeToZone(&(UDFGlobalData.CCBZoneHeader), Ccb);
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
} else {
MyFreePool__(Ccb);
}
return;
} // end UDFReleaseCCB()
/*
Function: UDFCleanupCCB()
Description:
Cleanup and deallocate a previously allocated structure.
Expected Interrupt Level (for execution) :
IRQL_PASSIVE_LEVEL
Return Value: None
*/
VOID
__fastcall
UDFCleanUpCCB(
PtrUDFCCB Ccb)
{
// ASSERT(Ccb);
if(!Ccb) return; // probably, we havn't allocated it...
ASSERT(Ccb->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB);
_SEH2_TRY {
if(Ccb->Fcb) {
UDFTouch(&(Ccb->Fcb->CcbListResource));
UDFAcquireResourceExclusive(&(Ccb->Fcb->CcbListResource),TRUE);
RemoveEntryList(&(Ccb->NextCCB));
UDFReleaseResource(&(Ccb->Fcb->CcbListResource));
} else {
BrutePoint();
}
if (Ccb->DirectorySearchPattern) {
if (Ccb->DirectorySearchPattern->Buffer) {
MyFreePool__(Ccb->DirectorySearchPattern->Buffer);
Ccb->DirectorySearchPattern->Buffer = NULL;
}
MyFreePool__(Ccb->DirectorySearchPattern);
Ccb->DirectorySearchPattern = NULL;
}
UDFReleaseCCB(Ccb);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
} // end UDFCleanUpCCB()
/*************************************************************************
*
* Function: UDFAllocateFCB()
*
* Description:
* Allocate a new FCB structure to represent an open on-disk object.
* Also initialize the FCB structure to NULL.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: A pointer to the FCB structure OR NULL.
*
*************************************************************************/
PtrUDFFCB
UDFAllocateFCB(VOID)
{
PtrUDFFCB Fcb = NULL;
Fcb = (PtrUDFFCB)MyAllocatePool__(UDF_FCB_MT, UDFQuadAlign(sizeof(UDFFCB)));
if (!Fcb) {
return NULL;
}
// zero out the allocated memory block
RtlZeroMemory(Fcb, UDFQuadAlign(sizeof(UDFFCB)));
// set up some fields ...
Fcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB;
Fcb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFFCB));
UDFPrint(("UDFAllocateFCB: %x\n", Fcb));
return(Fcb);
} // end UDFAllocateFCB()
/*************************************************************************
*
* Function: UDFReleaseFCB()
*
* Description:
* Deallocate a previously allocated structure.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
/*VOID
UDFReleaseFCB(
PtrUDFFCB Fcb
)
{
ASSERT(Fcb);
MyFreePool__(Fcb);
return;
}*/
/*************************************************************************
*
*
*************************************************************************/
VOID
__fastcall
UDFCleanUpFCB(
PtrUDFFCB Fcb
)
{
UDFPrint(("UDFCleanUpFCB: %x\n", Fcb));
if(!Fcb) return;
ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
_SEH2_TRY {
// Deinitialize FCBName field
if (Fcb->FCBName) {
if(Fcb->FCBName->ObjectName.Buffer) {
MyFreePool__(Fcb->FCBName->ObjectName.Buffer);
Fcb->FCBName->ObjectName.Buffer = NULL;
#ifdef UDF_DBG
Fcb->FCBName->ObjectName.Length =
Fcb->FCBName->ObjectName.MaximumLength = 0;
#endif
}
#ifdef UDF_DBG
else {
UDFPrint(("UDF: Fcb has invalid FCBName Buffer\n"));
BrutePoint();
}
#endif
UDFReleaseObjectName(Fcb->FCBName);
Fcb->FCBName = NULL;
}
#ifdef UDF_DBG
else {
UDFPrint(("UDF: Fcb has invalid FCBName field\n"));
BrutePoint();
}
#endif
// begin transaction {
UDFTouch(&(Fcb->Vcb->FcbListResource));
UDFAcquireResourceExclusive(&(Fcb->Vcb->FcbListResource), TRUE);
// Remove this FCB from list of all FCB in VCB
RemoveEntryList(&(Fcb->NextFCB));
UDFReleaseResource(&(Fcb->Vcb->FcbListResource));
// } end transaction
if(Fcb->FCBFlags & UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE)
UDFDeleteResource(&(Fcb->CcbListResource));
// Free memory
UDFReleaseFCB(Fcb);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
} // end UDFCleanUpFCB()
#ifdef UDF_DBG
ULONG IrpContextCounter = 0;
#endif //UDF_DBG
/*************************************************************************
*
* Function: UDFAllocateIrpContext()
*
* Description:
* The UDF FSD creates an IRP context for each request received. This
* routine simply allocates (and initializes to NULL) a UDFIrpContext
* structure.
* Most of the fields in the context structure are then initialized here.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: A pointer to the IrpContext structure OR NULL.
*
*************************************************************************/
PtrUDFIrpContext
UDFAllocateIrpContext(
PIRP Irp,
PDEVICE_OBJECT PtrTargetDeviceObject
)
{
PtrUDFIrpContext PtrIrpContext = NULL;
BOOLEAN AllocatedFromZone = TRUE;
KIRQL CurrentIrql;
PIO_STACK_LOCATION IrpSp = NULL;
// first, __try to allocate out of the zone
KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
if (!ExIsFullZone(&(UDFGlobalData.IrpContextZoneHeader))) {
// we have enough memory
PtrIrpContext = (PtrUDFIrpContext)ExAllocateFromZone(&(UDFGlobalData.IrpContextZoneHeader));
// release the spinlock
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
} else {
// release the spinlock
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
// if we failed to obtain from the zone, get it directly from the VMM
PtrIrpContext = (PtrUDFIrpContext)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFIrpContext)));
AllocatedFromZone = FALSE;
}
// if we could not obtain the required memory, bug-check.
// Do NOT do this in your commercial driver, instead handle the error gracefully ...
if (!PtrIrpContext) {
return NULL;
}
#ifdef UDF_DBG
IrpContextCounter++;
#endif //UDF_DBG
// zero out the allocated memory block
RtlZeroMemory(PtrIrpContext, UDFQuadAlign(sizeof(UDFIrpContext)));
// set up some fields ...
PtrIrpContext->NodeIdentifier.NodeType = UDF_NODE_TYPE_IRP_CONTEXT;
PtrIrpContext->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFIrpContext));
PtrIrpContext->Irp = Irp;
PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject;
// copy over some fields from the IRP and set appropriate flag values
if (Irp) {
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IrpSp);
PtrIrpContext->MajorFunction = IrpSp->MajorFunction;
PtrIrpContext->MinorFunction = IrpSp->MinorFunction;
// Often, a FSD cannot honor a request for asynchronous processing
// of certain critical requests. For example, a "close" request on
// a file object can typically never be deferred. Therefore, do not
// be surprised if sometimes our FSD (just like all other FSD
// implementations on the Windows NT system) has to override the flag
// below.
if (IrpSp->FileObject == NULL) {
PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
} else {
if (IoIsOperationSynchronous(Irp)) {
PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
}
}
}
if (!AllocatedFromZone) {
UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_FROM_ZONE);
}
// Are we top-level ? This information is used by the dispatching code
// later (and also by the FSD dispatch routine)
if (IoGetTopLevelIrp() != Irp) {
// We are not top-level. Note this fact in the context structure
UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_TOP_LEVEL);
}
return(PtrIrpContext);
} // end UDFAllocateIrpContext()
/*************************************************************************
*
* Function: UDFReleaseIrpContext()
*
* Description:
* Deallocate a previously allocated structure.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
VOID
UDFReleaseIrpContext(
PtrUDFIrpContext PtrIrpContext)
{
if(!PtrIrpContext) return;
// ASSERT(PtrIrpContext);
#ifdef UDF_DBG
IrpContextCounter--;
#endif //UDF_DBG
// give back memory either to the zone or to the VMM
if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_FROM_ZONE)) {
// back to the zone
KIRQL CurrentIrql;
KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
ExFreeToZone(&(UDFGlobalData.IrpContextZoneHeader), PtrIrpContext);
KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
} else {
MyFreePool__(PtrIrpContext);
}
return;
} // end UDFReleaseIrpContext()
/*************************************************************************
*
* Function: UDFPostRequest()
*
* Description:
* Queue up a request for deferred processing (in the context of a system
* worker thread). The caller must have locked the user buffer (if required)
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_PENDING
*
*************************************************************************/
NTSTATUS
UDFPostRequest(
IN PtrUDFIrpContext PtrIrpContext,
IN PIRP Irp
)
{
KIRQL SavedIrql;
// PIO_STACK_LOCATION IrpSp;
PVCB Vcb;
// IrpSp = IoGetCurrentIrpStackLocation(Irp);
/*
if(Vcb->StopOverflowQueue) {
if(Irp) {
Irp->IoStatus.Status = STATUS_WRONG_VOLUME;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
UDFReleaseIrpContext(PtrIrpContext);
return STATUS_WRONG_VOLUME;
}
*/
// mark the IRP pending if this is not double post
if(Irp)
IoMarkIrpPending(Irp);
Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
if ( Vcb->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
// We cannot currently respond to this IRP so we'll just enqueue it
// to the overflow queue on the volume.
// Note: we just reuse LIST_ITEM field inside WorkQueueItem, this
// doesn't matter to regular processing of WorkItems.
InsertTailList( &(Vcb->OverflowQueue),
&(PtrIrpContext->WorkQueueItem.List) );
Vcb->OverflowQueueCount++;
KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql );
} else {
// We are going to send this Irp to an ex worker thread so up
// the count.
Vcb->PostedRequestCount++;
KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql );
// queue up the request
ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), UDFCommonDispatch, PtrIrpContext);
ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), CriticalWorkQueue);
// ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), DelayedWorkQueue);
}
// return status pending
return STATUS_PENDING;
} // end UDFPostRequest()
/*************************************************************************
*
* Function: UDFCommonDispatch()
*
* Description:
* The common dispatch routine invoked in the context of a system worker
* thread. All we do here is pretty much case off the major function
* code and invoke the appropriate FSD dispatch routine for further
* processing.
*
* Expected Interrupt Level (for execution) :
*
* IRQL PASSIVE_LEVEL
*
* Return Value: None
*
*************************************************************************/
VOID
NTAPI
UDFCommonDispatch(
IN PVOID Context // actually is a pointer to IRPContext structure
)
{
NTSTATUS RC = STATUS_SUCCESS;
PtrUDFIrpContext PtrIrpContext = NULL;
PIRP Irp = NULL;
PVCB Vcb;
KIRQL SavedIrql;
PLIST_ENTRY Entry;
BOOLEAN SpinLock = FALSE;
// The context must be a pointer to an IrpContext structure
PtrIrpContext = (PtrUDFIrpContext)Context;
// Assert that the Context is legitimate
if ( !PtrIrpContext ||
(PtrIrpContext->NodeIdentifier.NodeType != UDF_NODE_TYPE_IRP_CONTEXT) ||
(PtrIrpContext->NodeIdentifier.NodeSize != UDFQuadAlign(sizeof(UDFIrpContext))) /*||
!(PtrIrpContext->Irp)*/) {
UDFPrint((" Invalid Context\n"));
BrutePoint();
return;
}
Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
ASSERT(Vcb);
UDFPrint((" *** Thr: %x ThCnt: %x QCnt: %x Started!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount));
while(TRUE) {
UDFPrint((" Next IRP\n"));
FsRtlEnterFileSystem();
// Get a pointer to the IRP structure
// in some cases we can get Zero pointer to Irp
Irp = PtrIrpContext->Irp;
// Now, check if the FSD was top level when the IRP was originally invoked
// and set the thread context (for the worker thread) appropriately
if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) {
// The FSD is not top level for the original request
// Set a constant value in TLS to reflect this fact
IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
} else {
IoSetTopLevelIrp(Irp);
}
// Since the FSD routine will now be invoked in the context of this worker
// thread, we should inform the FSD that it is perfectly OK to block in
// the context of this thread
PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
_SEH2_TRY {
// Pre-processing has been completed; check the Major Function code value
// either in the IrpContext (copied from the IRP), or directly from the
// IRP itself (we will need a pointer to the stack location to do that),
// Then, switch based on the value on the Major Function code
UDFPrint((" *** MJ: %x, Thr: %x\n", PtrIrpContext->MajorFunction, PsGetCurrentThread()));
switch (PtrIrpContext->MajorFunction) {
case IRP_MJ_CREATE:
// Invoke the common create routine
RC = UDFCommonCreate(PtrIrpContext, Irp);
break;
case IRP_MJ_READ:
// Invoke the common read routine
RC = UDFCommonRead(PtrIrpContext, Irp);
break;
#ifndef UDF_READ_ONLY_BUILD
case IRP_MJ_WRITE:
// Invoke the common write routine
RC = UDFCommonWrite(PtrIrpContext, Irp);
break;
#endif //UDF_READ_ONLY_BUILD
case IRP_MJ_CLEANUP:
// Invoke the common cleanup routine
RC = UDFCommonCleanup(PtrIrpContext, Irp);
break;
case IRP_MJ_CLOSE:
// Invoke the common close routine
RC = UDFCommonClose(PtrIrpContext, Irp);
break;
case IRP_MJ_DIRECTORY_CONTROL:
// Invoke the common directory control routine
RC = UDFCommonDirControl(PtrIrpContext, Irp);
break;
case IRP_MJ_QUERY_INFORMATION:
#ifndef UDF_READ_ONLY_BUILD
case IRP_MJ_SET_INFORMATION:
#endif //UDF_READ_ONLY_BUILD
// Invoke the common query/set information routine
RC = UDFCommonFileInfo(PtrIrpContext, Irp);
break;
case IRP_MJ_QUERY_VOLUME_INFORMATION:
// Invoke the common query volume routine
RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp);
break;
#ifndef UDF_READ_ONLY_BUILD
case IRP_MJ_SET_VOLUME_INFORMATION:
// Invoke the common query volume routine
RC = UDFCommonSetVolInfo(PtrIrpContext, Irp);
break;
#endif //UDF_READ_ONLY_BUILD
#ifdef UDF_HANDLE_EAS
/* case IRP_MJ_QUERY_EA:
// Invoke the common query EAs routine
RC = UDFCommonGetExtendedAttr(PtrIrpContext, Irp);
break;
case IRP_MJ_SET_EA:
// Invoke the common set EAs routine
RC = UDFCommonSetExtendedAttr(PtrIrpContext, Irp);
break;*/
#endif // UDF_HANDLE_EAS
#ifdef UDF_ENABLE_SECURITY
case IRP_MJ_QUERY_SECURITY:
// Invoke the common query Security routine
RC = UDFCommonGetSecurity(PtrIrpContext, Irp);
break;
#ifndef UDF_READ_ONLY_BUILD
case IRP_MJ_SET_SECURITY:
// Invoke the common set Security routine
RC = UDFCommonSetSecurity(PtrIrpContext, Irp);
break;
#endif //UDF_READ_ONLY_BUILD
#endif // UDF_ENABLE_SECURITY
// Continue with the remaining possible dispatch routines below ...
default:
UDFPrint((" unhandled *** MJ: %x, Thr: %x\n", PtrIrpContext->MajorFunction, PsGetCurrentThread()));
// This is the case where we have an invalid major function
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// Free up the Irp Context
UDFReleaseIrpContext(PtrIrpContext);
break;
}
// Note: PtrIrpContext is invalid here
UDFPrint((" *** Thr: %x Done!\n", PsGetCurrentThread()));
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
} _SEH2_END;
// Enable preemption
FsRtlExitFileSystem();
// Ensure that the "top-level" field is cleared
IoSetTopLevelIrp(NULL);
// If there are any entries on this volume's overflow queue, service
// them.
if(!Vcb) {
BrutePoint();
break;
}
KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
SpinLock = TRUE;
if(!Vcb->OverflowQueueCount)
break;
Vcb->OverflowQueueCount--;
Entry = RemoveHeadList(&Vcb->OverflowQueue);
KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql);
SpinLock = FALSE;
PtrIrpContext = CONTAINING_RECORD( Entry,
UDFIrpContext,
WorkQueueItem.List );
}
if(!SpinLock)
KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
Vcb->PostedRequestCount--;
KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql);
UDFPrint((" *** Thr: %x ThCnt: %x QCnt: %x Terminated!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount));
return;
} // end UDFCommonDispatch()
/*************************************************************************
*
* Function: UDFInitializeVCB()
*
* Description:
* Perform the initialization for a VCB structure.
*
* Expected Interrupt Level (for execution) :
*
* IRQL PASSIVE_LEVEL
*
* Return Value: status
*
*************************************************************************/
NTSTATUS
UDFInitializeVCB(
IN PDEVICE_OBJECT PtrVolumeDeviceObject,
IN PDEVICE_OBJECT PtrTargetDeviceObject,
IN PVPB PtrVPB
)
{
NTSTATUS RC = STATUS_SUCCESS;
PVCB Vcb = NULL;
SHORT i;
BOOLEAN VCBResourceInit = FALSE;
BOOLEAN BitMapResource1Init = FALSE;
BOOLEAN FcbListResourceInit = FALSE;
BOOLEAN FileIdResourceInit = FALSE;
BOOLEAN DlocResourceInit = FALSE;
BOOLEAN DlocResource2Init = FALSE;
BOOLEAN FlushResourceInit = FALSE;
BOOLEAN PreallocResourceInit= FALSE;
BOOLEAN IoResourceInit = FALSE;
Vcb = (PVCB)(PtrVolumeDeviceObject->DeviceExtension);
_SEH2_TRY {
// Zero it out (typically this has already been done by the I/O
// Manager but it does not hurt to do it again)!
RtlZeroMemory(Vcb, sizeof(VCB));
// Initialize the signature fields
Vcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_VCB;
Vcb->NodeIdentifier.NodeSize = sizeof(VCB);
// Initialize the ERESOURCE object.
RC = UDFInitializeResourceLite(&(Vcb->VCBResource));
if(!NT_SUCCESS(RC))
try_return(RC);
VCBResourceInit = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->BitMapResource1));
if(!NT_SUCCESS(RC))
try_return(RC);
BitMapResource1Init = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->FcbListResource));
if(!NT_SUCCESS(RC))
try_return(RC);
FcbListResourceInit = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->FileIdResource));
if(!NT_SUCCESS(RC))
try_return(RC);
FileIdResourceInit = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->DlocResource));
if(!NT_SUCCESS(RC))
try_return(RC);
DlocResourceInit = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->DlocResource2));
if(!NT_SUCCESS(RC))
try_return(RC);
DlocResource2Init = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->FlushResource));
if(!NT_SUCCESS(RC))
try_return(RC);
FlushResourceInit = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->PreallocResource));
if(!NT_SUCCESS(RC))
try_return(RC);
PreallocResourceInit = TRUE;
RC = UDFInitializeResourceLite(&(Vcb->IoResource));
if(!NT_SUCCESS(RC))
try_return(RC);
IoResourceInit = TRUE;
// RC = UDFInitializeResourceLite(&(Vcb->DelayedCloseResource));
// ASSERT(NT_SUCCESS(RC));
// Allocate buffer for statistics
Vcb->Statistics = (PFILE_SYSTEM_STATISTICS)MyAllocatePool__(NonPagedPool, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors );
if(!Vcb->Statistics)
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
RtlZeroMemory( Vcb->Statistics, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors );
for (i=0; i < (KeNumberProcessors); i++) {
Vcb->Statistics[i].Common.FileSystemType = FILESYSTEM_STATISTICS_TYPE_NTFS;
Vcb->Statistics[i].Common.Version = 1;
Vcb->Statistics[i].Common.SizeOfCompleteStructure =
sizeof(FILE_SYSTEM_STATISTICS);
}
// We know the target device object.
// Note that this is not neccessarily a pointer to the actual
// physical/virtual device on which the logical volume should
// be mounted. This is actually a pointer to either the actual
// (real) device or to any device object that may have been
// attached to it. Any IRPs that we send down should be sent to this
// device object. However, the "real" physical/virtual device object
// on which we perform our mount operation can be determined from the
// RealDevice field in the VPB sent to us.
Vcb->TargetDeviceObject = PtrTargetDeviceObject;
// We also have a pointer to the newly created device object representing
// this logical volume (remember that this VCB structure is simply an
// extension of the created device object).
Vcb->VCBDeviceObject = PtrVolumeDeviceObject;
// We also have the VPB pointer. This was obtained from the
// Parameters.MountVolume.Vpb field in the current I/O stack location
// for the mount IRP.
Vcb->Vpb = PtrVPB;
// Target Vcb field in Vcb onto itself. This required for check in
// open/lock/unlock volume dispatch poits
Vcb->Vcb=Vcb;
// Set the removable media flag based on the real device's
// characteristics
if (PtrVPB->RealDevice->Characteristics & FILE_REMOVABLE_MEDIA) {
Vcb->VCBFlags |= UDF_VCB_FLAGS_REMOVABLE_MEDIA;
}
// Initialize the list anchor (head) for some lists in this VCB.
InitializeListHead(&(Vcb->NextFCB));
InitializeListHead(&(Vcb->NextNotifyIRP));
InitializeListHead(&(Vcb->VolumeOpenListHead));
// Initialize the overflow queue for the volume
Vcb->OverflowQueueCount = 0;
InitializeListHead(&(Vcb->OverflowQueue));
Vcb->PostedRequestCount = 0;
KeInitializeSpinLock(&(Vcb->OverflowQueueSpinLock));
// Initialize the notify IRP list mutex
FsRtlNotifyInitializeSync(&(Vcb->NotifyIRPMutex));
// Intilize NtRequiredFCB for this VCB
Vcb->NTRequiredFCB = (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
if(!Vcb->NTRequiredFCB)
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
RtlZeroMemory(Vcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
// Set the initial file size values appropriately. Note that our FSD may
// wish to guess at the initial amount of information we would like to
// read from the disk until we have really determined that this a valid
// logical volume (on disk) that we wish to mount.
// Vcb->FileSize = Vcb->AllocationSize = ??
// We do not want to bother with valid data length callbacks
// from the Cache Manager for the file stream opened for volume metadata
// information
Vcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFULL;
Vcb->VolumeLockPID = -1;
Vcb->VCBOpenCount = 1;
Vcb->WCacheMaxBlocks = UDFGlobalData.WCacheMaxBlocks;
Vcb->WCacheMaxFrames = UDFGlobalData.WCacheMaxFrames;
Vcb->WCacheBlocksPerFrameSh = UDFGlobalData.WCacheBlocksPerFrameSh;
Vcb->WCacheFramesToKeepFree = UDFGlobalData.WCacheFramesToKeepFree;
// Create a stream file object for this volume.
//Vcb->PtrStreamFileObject = IoCreateStreamFileObject(NULL,
// Vcb->Vpb->RealDevice);
//ASSERT(Vcb->PtrStreamFileObject);
// Initialize some important fields in the newly created file object.
//Vcb->PtrStreamFileObject->FsContext = (PVOID)Vcb;
//Vcb->PtrStreamFileObject->FsContext2 = NULL;
//Vcb->PtrStreamFileObject->SectionObjectPointer = &(Vcb->SectionObject);
//Vcb->PtrStreamFileObject->Vpb = PtrVPB;
// Link this chap onto the global linked list of all VCB structures.
// We consider that GlobalDataResource was acquired in past
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
InsertTailList(&(UDFGlobalData.VCBQueue), &(Vcb->NextVCB));
Vcb->TargetDevName.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(MOUNTDEV_NAME));
if(!Vcb->TargetDevName.Buffer)
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject,
NULL,0,
(PVOID)(Vcb->TargetDevName.Buffer),sizeof(MOUNTDEV_NAME),
FALSE, NULL);
if(!NT_SUCCESS(RC)) {
if(RC == STATUS_BUFFER_OVERFLOW) {
if(!MyReallocPool__((PCHAR)(Vcb->TargetDevName.Buffer), sizeof(MOUNTDEV_NAME),
(PCHAR*)&(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME)) ) {
goto Kill_DevName_buffer;
}
RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject,
NULL,0,
(PVOID)(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME),
FALSE, NULL);
if(!NT_SUCCESS(RC))
goto Kill_DevName_buffer;
} else {
Kill_DevName_buffer:
if(!MyReallocPool__((PCHAR)Vcb->TargetDevName.Buffer, sizeof(MOUNTDEV_NAME),
(PCHAR*)&(Vcb->TargetDevName.Buffer), sizeof(REG_NAMELESS_DEV)))
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
RtlCopyMemory(Vcb->TargetDevName.Buffer, REG_NAMELESS_DEV, sizeof(REG_NAMELESS_DEV));
Vcb->TargetDevName.Length = sizeof(REG_NAMELESS_DEV)-sizeof(WCHAR);
Vcb->TargetDevName.MaximumLength = sizeof(REG_NAMELESS_DEV);
goto read_reg;
}
}
Vcb->TargetDevName.MaximumLength =
(Vcb->TargetDevName.Length = Vcb->TargetDevName.Buffer[0]) + sizeof(WCHAR);
RtlMoveMemory((PVOID)(Vcb->TargetDevName.Buffer), (PVOID)(Vcb->TargetDevName.Buffer+1), Vcb->TargetDevName.Buffer[0]);
Vcb->TargetDevName.Buffer[i = (SHORT)(Vcb->TargetDevName.Length/sizeof(WCHAR))] = 0;
for(;i>=0;i--) {
if(Vcb->TargetDevName.Buffer[i] == L'\\') {
Vcb->TargetDevName.Length -= i*sizeof(WCHAR);
RtlMoveMemory((PVOID)(Vcb->TargetDevName.Buffer), (PVOID)(Vcb->TargetDevName.Buffer+i), Vcb->TargetDevName.Length);
Vcb->TargetDevName.Buffer[Vcb->TargetDevName.Length/sizeof(WCHAR)] = 0;
break;
}
}
UDFPrint((" TargetDevName: %S\n", Vcb->TargetDevName.Buffer));
// Initialize caching for the stream file object.
//CcInitializeCacheMap(Vcb->PtrStreamFileObject, (PCC_FILE_SIZES)(&(Vcb->AllocationSize)),
// TRUE, // We will use pinned access.
// &(UDFGlobalData.CacheMgrCallBacks), Vcb);
read_reg:
UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
// Mark the fact that this VCB structure is initialized.
Vcb->VCBFlags |= UDF_VCB_FLAGS_VCB_INITIALIZED;
RC = STATUS_SUCCESS;
try_exit: NOTHING;
} _SEH2_FINALLY {
if(!NT_SUCCESS(RC)) {
if(Vcb->TargetDevName.Buffer)
MyFreePool__(Vcb->TargetDevName.Buffer);
if(Vcb->NTRequiredFCB)
MyFreePool__(Vcb->NTRequiredFCB);
if(Vcb->Statistics)
MyFreePool__(Vcb->Statistics);
if(VCBResourceInit)
UDFDeleteResource(&(Vcb->VCBResource));
if(BitMapResource1Init)
UDFDeleteResource(&(Vcb->BitMapResource1));
if(FcbListResourceInit)
UDFDeleteResource(&(Vcb->FcbListResource));
if(FileIdResourceInit)
UDFDeleteResource(&(Vcb->FileIdResource));
if(DlocResourceInit)
UDFDeleteResource(&(Vcb->DlocResource));
if(DlocResource2Init)
UDFDeleteResource(&(Vcb->DlocResource2));
if(FlushResourceInit)
UDFDeleteResource(&(Vcb->FlushResource));
if(PreallocResourceInit)
UDFDeleteResource(&(Vcb->PreallocResource));
if(IoResourceInit)
UDFDeleteResource(&(Vcb->IoResource));
}
} _SEH2_END;
return RC;
} // end UDFInitializeVCB()
UDFFSD_MEDIA_TYPE
UDFGetMediaClass(
PVCB Vcb
)
{
switch(Vcb->FsDeviceType) {
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
if(Vcb->VCBFlags & (UDF_VCB_FLAGS_VOLUME_READ_ONLY |
UDF_VCB_FLAGS_MEDIA_READ_ONLY))
return MediaCdrom;
if(Vcb->CDR_Mode)
return MediaCdr;
if((Vcb->MediaType >= MediaType_UnknownSize_CDR) &&
(Vcb->MediaType < MediaType_UnknownSize_CDRW)) {
return MediaCdr;
}
if((Vcb->MediaType >= MediaType_UnknownSize_CDRW) &&
(Vcb->MediaType < MediaType_UnknownSize_Unknown)) {
return MediaCdrw;
}
if(Vcb->MediaClassEx == CdMediaClass_CDR) {
return MediaCdr;
}
if(Vcb->MediaClassEx == CdMediaClass_DVDR ||
Vcb->MediaClassEx == CdMediaClass_DVDpR ||
Vcb->MediaClassEx == CdMediaClass_HD_DVDR ||
Vcb->MediaClassEx == CdMediaClass_BDR) {
return MediaDvdr;
}
if(Vcb->MediaClassEx == CdMediaClass_CDRW) {
return MediaCdrw;
}
if(Vcb->MediaClassEx == CdMediaClass_DVDRW ||
Vcb->MediaClassEx == CdMediaClass_DVDpRW ||
Vcb->MediaClassEx == CdMediaClass_DVDRAM ||
Vcb->MediaClassEx == CdMediaClass_HD_DVDRW ||
Vcb->MediaClassEx == CdMediaClass_HD_DVDRAM ||
Vcb->MediaClassEx == CdMediaClass_BDRE) {
return MediaDvdrw;
}
//
if(Vcb->MediaClassEx == CdMediaClass_CDROM ||
Vcb->MediaClassEx == CdMediaClass_DVDROM ||
Vcb->MediaClassEx == CdMediaClass_HD_DVDROM ||
Vcb->MediaClassEx == CdMediaClass_BDROM) {
return MediaCdrom;
}
return MediaCdrom;
#ifdef UDF_HDD_SUPPORT
case FILE_DEVICE_DISK_FILE_SYSTEM:
if(Vcb->TargetDeviceObject->Characteristics & FILE_FLOPPY_DISKETTE)
return MediaFloppy;
if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
return MediaZip;
return MediaHdd;
#endif //UDF_HDD_SUPPORT
}
return MediaUnknown;
} // end UDFGetMediaClass()
typedef ULONG
(*ptrUDFGetParameter)(
IN PVCB Vcb,
IN PCWSTR Name,
IN ULONG DefValue
);
VOID
UDFUpdateCompatOption(
PVCB Vcb,
BOOLEAN Update,
BOOLEAN UseCfg,
PCWSTR Name,
ULONG Flag,
BOOLEAN Default
)
{
ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter;
if(UDFGetParameter(Vcb, Name, Update ? ((Vcb->CompatFlags & Flag) ? TRUE : FALSE) : Default)) {
Vcb->CompatFlags |= Flag;
} else {
Vcb->CompatFlags &= ~Flag;
}
} // end UDFUpdateCompatOption()
VOID
UDFReadRegKeys(
PVCB Vcb,
BOOLEAN Update,
BOOLEAN UseCfg
)
{
ULONG mult = 1;
ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter;
Vcb->DefaultRegName = UDFMediaClassName[(ULONG)UDFGetMediaClass(Vcb)].ClassName;
// Should we use Extended FE by default ?
Vcb->UseExtendedFE = (UCHAR)UDFGetParameter(Vcb, REG_USEEXTENDEDFE_NAME,
Update ? Vcb->UseExtendedFE : FALSE);
if(Vcb->UseExtendedFE != TRUE) Vcb->UseExtendedFE = FALSE;
// What type of AllocDescs should we use
Vcb->DefaultAllocMode = (USHORT)UDFGetParameter(Vcb, REG_DEFALLOCMODE_NAME,
Update ? Vcb->DefaultAllocMode : ICB_FLAG_AD_SHORT);
if(Vcb->DefaultAllocMode > ICB_FLAG_AD_LONG) Vcb->DefaultAllocMode = ICB_FLAG_AD_SHORT;
// Default UID & GID to be set on newly created files
Vcb->DefaultUID = UDFGetParameter(Vcb, UDF_DEFAULT_UID_NAME, Update ? Vcb->DefaultUID : -1);
Vcb->DefaultGID = UDFGetParameter(Vcb, UDF_DEFAULT_GID_NAME, Update ? Vcb->DefaultGID : -1);
// FE allocation charge for plain Dirs
Vcb->FECharge = UDFGetParameter(Vcb, UDF_FE_CHARGE_NAME, Update ? Vcb->FECharge : 0);
if(!Vcb->FECharge)
Vcb->FECharge = UDF_DEFAULT_FE_CHARGE;
// FE allocation charge for Stream Dirs (SDir)
Vcb->FEChargeSDir = UDFGetParameter(Vcb, UDF_FE_CHARGE_SDIR_NAME,
Update ? Vcb->FEChargeSDir : 0);
if(!Vcb->FEChargeSDir)
Vcb->FEChargeSDir = UDF_DEFAULT_FE_CHARGE_SDIR;
// How many Deleted entries should contain Directory to make us
// start packing it.
Vcb->PackDirThreshold = UDFGetParameter(Vcb, UDF_DIR_PACK_THRESHOLD_NAME,
Update ? Vcb->PackDirThreshold : 0);
if(Vcb->PackDirThreshold == 0xffffffff)
Vcb->PackDirThreshold = UDF_DEFAULT_DIR_PACK_THRESHOLD;
// The binary exponent for the number of Pages to be read-ahead'ed
// This information would be sent to System Cache Manager
if(!Update) {
Vcb->SystemCacheGran = (1 << UDFGetParameter(Vcb, UDF_READAHEAD_GRAN_NAME, 0)) * PAGE_SIZE;
if(!Vcb->SystemCacheGran)
Vcb->SystemCacheGran = UDF_DEFAULT_READAHEAD_GRAN;
}
// Timeouts for FreeSpaceBitMap & TheWholeDirTree flushes
Vcb->BM_FlushPriod = UDFGetParameter(Vcb, UDF_BM_FLUSH_PERIOD_NAME,
Update ? Vcb->BM_FlushPriod : 0);
if(!Vcb->BM_FlushPriod) {
Vcb->BM_FlushPriod = UDF_DEFAULT_BM_FLUSH_TIMEOUT;
} else
if(Vcb->BM_FlushPriod == (ULONG)-1) {
Vcb->BM_FlushPriod = 0;
}
Vcb->Tree_FlushPriod = UDFGetParameter(Vcb, UDF_TREE_FLUSH_PERIOD_NAME,
Update ? Vcb->Tree_FlushPriod : 0);
if(!Vcb->Tree_FlushPriod) {
Vcb->Tree_FlushPriod = UDF_DEFAULT_TREE_FLUSH_TIMEOUT;
} else
if(Vcb->Tree_FlushPriod == (ULONG)-1) {
Vcb->Tree_FlushPriod = 0;
}
Vcb->SkipCountLimit = UDFGetParameter(Vcb, UDF_NO_UPDATE_PERIOD_NAME,
Update ? Vcb->SkipCountLimit : 0);
if(!Vcb->SkipCountLimit)
Vcb->SkipCountLimit = -1;
Vcb->SkipEjectCountLimit = UDFGetParameter(Vcb, UDF_NO_EJECT_PERIOD_NAME,
Update ? Vcb->SkipEjectCountLimit : 3);
if(!Update) {
// How many threads are allowed to sodomize Disc simultaneously on each CPU
Vcb->ThreadsPerCpu = UDFGetParameter(Vcb, UDF_FSP_THREAD_PER_CPU_NAME,
Update ? Vcb->ThreadsPerCpu : 2);
if(Vcb->ThreadsPerCpu < 2)
Vcb->ThreadsPerCpu = UDF_DEFAULT_FSP_THREAD_PER_CPU;
}
// The mimimum FileSize increment when we'll decide not to allocate
// on-disk space.
Vcb->SparseThreshold = UDFGetParameter(Vcb, UDF_SPARSE_THRESHOLD_NAME,
Update ? Vcb->SparseThreshold : 0);
if(!Vcb->SparseThreshold)
Vcb->SparseThreshold = UDF_DEFAULT_SPARSE_THRESHOLD;
// This option is used to VERIFY all the data written. It decreases performance
Vcb->VerifyOnWrite = UDFGetParameter(Vcb, UDF_VERIFY_ON_WRITE_NAME,
Update ? Vcb->VerifyOnWrite : FALSE) ? TRUE : FALSE;
#ifndef UDF_READ_ONLY_BUILD
// Should we update AttrFileTime on Attr changes
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_ATTR, UDF_VCB_IC_UPDATE_ATTR_TIME, FALSE);
// Should we update ModifyFileTime on Writes changes
// It also affects ARCHIVE bit setting on write operations
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_MOD, UDF_VCB_IC_UPDATE_MODIFY_TIME, FALSE);
// Should we update AccessFileTime on Exec & so on.
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_ACCS, UDF_VCB_IC_UPDATE_ACCESS_TIME, FALSE);
// Should we update Archive bit
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_ATTR_ARCH, UDF_VCB_IC_UPDATE_ARCH_BIT, FALSE);
// Should we update Dir's Times & Attrs on Modify
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_W, UDF_VCB_IC_UPDATE_DIR_WRITE, FALSE);
// Should we update Dir's Times & Attrs on Access
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_R, UDF_VCB_IC_UPDATE_DIR_READ, FALSE);
// Should we allow user to write into Read-Only Directory
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_WRITE_IN_RO_DIR, UDF_VCB_IC_WRITE_IN_RO_DIR, TRUE);
// Should we allow user to change Access Time for unchanged Directory
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR, UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME, FALSE);
#endif //UDF_READ_ONLY_BUILD
// Should we record Allocation Descriptors in W2k-compatible form
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_ALLOC_DESCS, UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS, TRUE);
// Should we read LONG_ADs with invalid PartitionReferenceNumber (generated by Nero Instant Burner)
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_INSTANT_COMPAT_ALLOC_DESCS, UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS, TRUE);
// Should we make a copy of VolumeLabel in LVD
// usually only PVD is updated
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_VLABEL, UDF_VCB_IC_W2K_COMPAT_VLABEL, TRUE);
// Should we handle or ignore HW_RO flag
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_HANDLE_HW_RO, UDF_VCB_IC_HW_RO, FALSE);
// Should we handle or ignore SOFT_RO flag
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_HANDLE_SOFT_RO, UDF_VCB_IC_SOFT_RO, TRUE);
// Check if we should generate UDF-style or OS-style DOS-names
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_OS_NATIVE_DOS_NAME, UDF_VCB_IC_OS_NATIVE_DOS_NAME, FALSE);
#ifndef UDF_READ_ONLY_BUILD
// should we force FO_WRITE_THROUGH on removable media
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_FORCE_WRITE_THROUGH_NAME, UDF_VCB_IC_FORCE_WRITE_THROUGH,
(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) ? TRUE : FALSE
);
#endif //UDF_READ_ONLY_BUILD
// Should we ignore FO_SEQUENTIAL_ONLY
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_IGNORE_SEQUENTIAL_IO, UDF_VCB_IC_IGNORE_SEQUENTIAL_IO, FALSE);
// Force Read-only mounts
#ifndef UDF_READ_ONLY_BUILD
UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_FORCE_HW_RO, UDF_VCB_IC_FORCE_HW_RO, FALSE);
#else //UDF_READ_ONLY_BUILD
Vcb->CompatFlags |= UDF_VCB_IC_FORCE_HW_RO;
#endif //UDF_READ_ONLY_BUILD
// Check if we should send FLUSH request for File/Dir down to
// underlaying driver
if(UDFGetParameter(Vcb, UDF_FLUSH_MEDIA,Update ? Vcb->FlushMedia : FALSE)) {
Vcb->FlushMedia = TRUE;
} else {
Vcb->FlushMedia = FALSE;
}
// compare data from packet with data to be writen there
// before physical writing
if(!UDFGetParameter(Vcb, UDF_COMPARE_BEFORE_WRITE, Update ? Vcb->DoNotCompareBeforeWrite : FALSE)) {
Vcb->DoNotCompareBeforeWrite = TRUE;
} else {
Vcb->DoNotCompareBeforeWrite = FALSE;
}
if(!Update) {
if(UDFGetParameter(Vcb, UDF_CHAINED_IO, TRUE)) {
Vcb->CacheChainedIo = TRUE;
}
if(UDFGetParameter(Vcb, UDF_FORCE_MOUNT_ALL, FALSE)) {
Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
}
// Should we show Blank.Cd file on damaged/unformatted,
// but UDF-compatible disks
Vcb->ShowBlankCd = (UCHAR)UDFGetParameter(Vcb, UDF_SHOW_BLANK_CD, FALSE);
if(Vcb->ShowBlankCd) {
Vcb->CompatFlags |= UDF_VCB_IC_SHOW_BLANK_CD;
if(Vcb->ShowBlankCd > 2) {
Vcb->ShowBlankCd = 2;
}
}
// Should we wait util CD device return from
// Becoming Ready state
if(UDFGetParameter(Vcb, UDF_WAIT_CD_SPINUP, TRUE)) {
Vcb->CompatFlags |= UDF_VCB_IC_WAIT_CD_SPINUP;
}
// Should we remenber bad VDS locations during mount
// Caching will improve mount performance on bad disks, but
// will degrade mauntability of unreliable discs
if(UDFGetParameter(Vcb, UDF_CACHE_BAD_VDS, TRUE)) {
Vcb->CompatFlags |= UDF_VCB_IC_CACHE_BAD_VDS;
}
// Set partitially damaged volume mount mode
Vcb->PartitialDamagedVolumeAction = (UCHAR)UDFGetParameter(Vcb, UDF_PART_DAMAGED_BEHAVIOR, UDF_PART_DAMAGED_RW);
if(Vcb->PartitialDamagedVolumeAction > 2) {
Vcb->PartitialDamagedVolumeAction = UDF_PART_DAMAGED_RW;
}
// Set partitially damaged volume mount mode
Vcb->NoFreeRelocationSpaceVolumeAction = (UCHAR)UDFGetParameter(Vcb, UDF_NO_SPARE_BEHAVIOR, UDF_PART_DAMAGED_RW);
if(Vcb->NoFreeRelocationSpaceVolumeAction > 1) {
Vcb->NoFreeRelocationSpaceVolumeAction = UDF_PART_DAMAGED_RW;
}
// Set dirty volume mount mode
if(UDFGetParameter(Vcb, UDF_DIRTY_VOLUME_BEHAVIOR, UDF_PART_DAMAGED_RO)) {
Vcb->CompatFlags |= UDF_VCB_IC_DIRTY_RO;
}
mult = UDFGetParameter(Vcb, UDF_CACHE_SIZE_MULTIPLIER, 1);
if(!mult) mult = 1;
Vcb->WCacheMaxBlocks *= mult;
Vcb->WCacheMaxFrames *= mult;
if(UDFGetParameter(Vcb, UDF_USE_EJECT_BUTTON, TRUE)) {
Vcb->UseEvent = TRUE;
}
}
return;
} // end UDFReadRegKeys()
ULONG
UDFGetRegParameter(
IN PVCB Vcb,
IN PCWSTR Name,
IN ULONG DefValue
)
{
return UDFRegCheckParameterValue(&(UDFGlobalData.SavedRegPath),
Name,
Vcb ? &(Vcb->TargetDevName) : NULL,
Vcb ? Vcb->DefaultRegName : NULL,
DefValue);
} // end UDFGetRegParameter()
ULONG
UDFGetCfgParameter(
IN PVCB Vcb,
IN PCWSTR Name,
IN ULONG DefValue
)
{
ULONG len;
CHAR NameA[128];
ULONG ret_val=0;
CHAR a;
BOOLEAN wait_name=TRUE;
BOOLEAN wait_val=FALSE;
BOOLEAN wait_nl=FALSE;
ULONG radix=10;
ULONG i;
PUCHAR Cfg = Vcb->Cfg;
ULONG Length = Vcb->CfgLength;
if(!Cfg || !Length)
return DefValue;
len = wcslen(Name);
if(len >= sizeof(NameA))
return DefValue;
sprintf(NameA, "%S", Name);
for(i=0; i<Length; i++) {
a=Cfg[i];
switch(a) {
case '\n':
case '\r':
case ',':
if(wait_val)
return DefValue;
continue;
case ';':
case '#':
case '[': // ignore sections for now, treat as comment
if(!wait_name)
return DefValue;
wait_nl = TRUE;
continue;
case '=':
if(!wait_val)
return DefValue;
continue;
case ' ':
case '\t':
continue;
default:
if(wait_nl)
continue;
}
if(wait_name) {
if(i+len+2 > Length)
return DefValue;
if(RtlCompareMemory(Cfg+i, NameA, len) == len) {
a=Cfg[i+len];
switch(a) {
case '\n':
case '\r':
case ',':
case ';':
case '#':
return DefValue;
case '=':
case ' ':
case '\t':
break;
default:
wait_nl = TRUE;
wait_val = FALSE;
i+=len;
continue;
}
wait_name = FALSE;
wait_nl = FALSE;
wait_val = TRUE;
i+=len;
} else {
wait_nl = TRUE;
}
continue;
}
if(wait_val) {
if(i+3 > Length) {
if(a=='0' && Cfg[i+1]=='x') {
i+=2;
radix=16;
}
}
if(i >= Length) {
return DefValue;
}
while(i<Length) {
a=Cfg[i];
switch(a) {
case '\n':
case '\r':
case ' ':
case '\t':
case ',':
case ';':
case '#':
if(wait_val)
return DefValue;
return ret_val;
}
if(a >= '0' && a <= '9') {
a -= '0';
} else {
if(radix != 16)
return DefValue;
if(a >= 'a' && a <= 'f') {
a -= 'a';
} else
if(a >= 'A' && a <= 'F') {
a -= 'A';
} else {
return DefValue;
}
a += 0x0a;
}
ret_val = ret_val*radix + a;
wait_val = FALSE;
i++;
}
return ret_val;
}
}
return DefValue;
} // end UDFGetCfgParameter()
VOID
UDFReleaseVCB(
PVCB Vcb
)
{
LARGE_INTEGER delay;
UDFPrint(("UDFReleaseVCB\n"));
delay.QuadPart = -500000; // 0.05 sec
while(Vcb->PostedRequestCount) {
UDFPrint(("UDFReleaseVCB: PostedRequestCount = %d\n", Vcb->PostedRequestCount));
// spin until all queues IRPs are processed
KeDelayExecutionThread(KernelMode, FALSE, &delay);
delay.QuadPart -= 500000; // grow delay 0.05 sec
}
_SEH2_TRY {
UDFPrint(("UDF: Flushing buffers\n"));
UDFVRelease(Vcb);
WCacheFlushAll__(&(Vcb->FastCache),Vcb);
WCacheRelease__(&(Vcb->FastCache));
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
#ifdef UDF_DBG
_SEH2_TRY {
if (!ExIsResourceAcquiredShared(&UDFGlobalData.GlobalDataResource)) {
UDFPrint(("UDF: attempt to access to not protected data\n"));
UDFPrint(("UDF: UDFGlobalData\n"));
BrutePoint();
}
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
#endif
_SEH2_TRY {
RemoveEntryList(&(Vcb->NextVCB));
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
/* _SEH2_TRY {
if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT)
KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL);
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT;
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
}*/
_SEH2_TRY {
UDFPrint(("UDF: Delete resources\n"));
UDFDeleteResource(&(Vcb->VCBResource));
UDFDeleteResource(&(Vcb->BitMapResource1));
UDFDeleteResource(&(Vcb->FcbListResource));
UDFDeleteResource(&(Vcb->FileIdResource));
UDFDeleteResource(&(Vcb->DlocResource));
UDFDeleteResource(&(Vcb->DlocResource2));
UDFDeleteResource(&(Vcb->FlushResource));
UDFDeleteResource(&(Vcb->PreallocResource));
UDFDeleteResource(&(Vcb->IoResource));
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
_SEH2_TRY {
UDFPrint(("UDF: Cleanup VCB\n"));
ASSERT(IsListEmpty(&(Vcb->NextNotifyIRP)));
FsRtlNotifyUninitializeSync(&(Vcb->NotifyIRPMutex));
UDFCleanupVCB(Vcb);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
_SEH2_TRY {
UDFPrint(("UDF: Delete DO\n"));
IoDeleteDevice(Vcb->VCBDeviceObject);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
} // end UDFReleaseVCB()
/*
Read DWORD from Registry
*/
ULONG
UDFRegCheckParameterValue(
IN PUNICODE_STRING RegistryPath,
IN PCWSTR Name,
IN PUNICODE_STRING PtrVolumePath,
IN PCWSTR DefaultPath,
IN ULONG DefValue
)
{
NTSTATUS status;
ULONG val = DefValue;
UNICODE_STRING paramStr;
UNICODE_STRING defaultParamStr;
UNICODE_STRING paramPathUnknownStr;
UNICODE_STRING paramSuffix;
UNICODE_STRING paramPath;
UNICODE_STRING paramPathUnknown;
UNICODE_STRING paramDevPath;
UNICODE_STRING defaultParamPath;
_SEH2_TRY {
paramPath.Buffer = NULL;
paramDevPath.Buffer = NULL;
paramPathUnknown.Buffer = NULL;
defaultParamPath.Buffer = NULL;
// First append \Parameters to the passed in registry path
// Note, RtlInitUnicodeString doesn't allocate memory
RtlInitUnicodeString(&paramStr, L"\\Parameters");
RtlInitUnicodeString(&paramPath, NULL);
RtlInitUnicodeString(&paramPathUnknownStr, REG_DEFAULT_UNKNOWN);
RtlInitUnicodeString(&paramPathUnknown, NULL);
paramPathUnknown.MaximumLength = RegistryPath->Length + paramPathUnknownStr.Length + paramStr.Length + sizeof(WCHAR);
paramPath.MaximumLength = RegistryPath->Length + paramStr.Length + sizeof(WCHAR);
paramPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramPath.MaximumLength);
if(!paramPath.Buffer) {
UDFPrint(("UDFCheckRegValue: couldn't allocate paramPath\n"));
try_return(val = DefValue);
}
paramPathUnknown.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramPathUnknown.MaximumLength);
if(!paramPathUnknown.Buffer) {
UDFPrint(("UDFCheckRegValue: couldn't allocate paramPathUnknown\n"));
try_return(val = DefValue);
}
RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
status = RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
status = RtlAppendUnicodeToString(&paramPath, paramStr.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
UDFPrint(("UDFCheckRegValue: (1) |%S|\n", paramPath.Buffer));
RtlZeroMemory(paramPathUnknown.Buffer, paramPathUnknown.MaximumLength);
status = RtlAppendUnicodeToString(&paramPathUnknown, RegistryPath->Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
status = RtlAppendUnicodeToString(&paramPathUnknown, paramStr.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
status = RtlAppendUnicodeToString(&paramPathUnknown, paramPathUnknownStr.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
UDFPrint(("UDFCheckRegValue: (2) |%S|\n", paramPathUnknown.Buffer));
// First append \Parameters\Default_XXX to the passed in registry path
if(DefaultPath) {
RtlInitUnicodeString(&defaultParamStr, DefaultPath);
RtlInitUnicodeString(&defaultParamPath, NULL);
defaultParamPath.MaximumLength = paramPath.Length + defaultParamStr.Length + sizeof(WCHAR);
defaultParamPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, defaultParamPath.MaximumLength);
if(!defaultParamPath.Buffer) {
UDFPrint(("UDFCheckRegValue: couldn't allocate defaultParamPath\n"));
try_return(val = DefValue);
}
RtlZeroMemory(defaultParamPath.Buffer, defaultParamPath.MaximumLength);
status = RtlAppendUnicodeToString(&defaultParamPath, paramPath.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
status = RtlAppendUnicodeToString(&defaultParamPath, defaultParamStr.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
UDFPrint(("UDFCheckRegValue: (3) |%S|\n", defaultParamPath.Buffer));
}
if(PtrVolumePath) {
paramSuffix = *PtrVolumePath;
} else {
RtlInitUnicodeString(&paramSuffix, NULL);
}
RtlInitUnicodeString(&paramDevPath, NULL);
// now build the device specific path
paramDevPath.MaximumLength = paramPath.Length + paramSuffix.Length + sizeof(WCHAR);
paramDevPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramDevPath.MaximumLength);
if(!paramDevPath.Buffer) {
try_return(val = DefValue);
}
RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
status = RtlAppendUnicodeToString(&paramDevPath, paramPath.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
if(paramSuffix.Buffer) {
status = RtlAppendUnicodeToString(&paramDevPath, paramSuffix.Buffer);
if(!NT_SUCCESS(status)) {
try_return(val = DefValue);
}
}
UDFPrint(( " Parameter = %ws\n", Name));
{
HKEY hk = NULL;
status = RegTGetKeyHandle(NULL, RegistryPath->Buffer, &hk);
if(NT_SUCCESS(status)) {
RegTCloseKeyHandle(hk);
}
}
// *** Read GLOBAL_DEFAULTS from
// "\DwUdf\Parameters_Unknown\"
status = RegTGetDwordValue(NULL, paramPath.Buffer, Name, &val);
// *** Read DEV_CLASS_SPEC_DEFAULTS (if any) from
// "\DwUdf\Parameters_%DevClass%\"
if(DefaultPath) {
status = RegTGetDwordValue(NULL, defaultParamPath.Buffer, Name, &val);
}
// *** Read DEV_SPEC_PARAMS from (if device supports GetDevName)
// "\DwUdf\Parameters\%DevName%\"
status = RegTGetDwordValue(NULL, paramDevPath.Buffer, Name, &val);
try_exit: NOTHING;
} _SEH2_FINALLY {
if(DefaultPath && defaultParamPath.Buffer) {
MyFreePool__(defaultParamPath.Buffer);
}
if(paramPath.Buffer) {
MyFreePool__(paramPath.Buffer);
}
if(paramDevPath.Buffer) {
MyFreePool__(paramDevPath.Buffer);
}
if(paramPathUnknown.Buffer) {
MyFreePool__(paramPathUnknown.Buffer);
}
} _SEH2_END;
UDFPrint(( "UDFCheckRegValue: %ws for drive %s is %x\n\n", Name, PtrVolumePath, val));
return val;
} // end UDFRegCheckParameterValue()
/*
Routine Description:
This routine is called to initialize an IrpContext for the current
UDFFS request. The IrpContext is on the stack and we need to initialize
it for the current request. The request is a close operation.
Arguments:
IrpContext - IrpContext to initialize.
IrpContextLite - source for initialization
Return Value:
None
*/
VOID
UDFInitializeIrpContextFromLite(
OUT PtrUDFIrpContext *IrpContext,
IN PtrUDFIrpContextLite IrpContextLite
)
{
(*IrpContext) = UDFAllocateIrpContext(NULL, IrpContextLite->RealDevice);
// Zero and then initialize the structure.
// Major/Minor Function codes
(*IrpContext)->MajorFunction = IRP_MJ_CLOSE;
(*IrpContext)->Fcb = IrpContextLite->Fcb;
(*IrpContext)->TreeLength = IrpContextLite->TreeLength;
(*IrpContext)->IrpContextFlags |= (IrpContextLite->IrpContextFlags & ~UDF_IRP_CONTEXT_NOT_FROM_ZONE);
// Set the wait parameter
UDFSetFlag( (*IrpContext)->IrpContextFlags, UDF_IRP_CONTEXT_CAN_BLOCK );
return;
} // end UDFInitializeIrpContextFromLite()
/*
Routine Description:
This routine is called to initialize an IrpContext for the current
UDFFS request. The IrpContext is on the stack and we need to initialize
it for the current request. The request is a close operation.
Arguments:
IrpContext - IrpContext to initialize.
IrpContextLite - source for initialization
Return Value:
None
*/
NTSTATUS
UDFInitializeIrpContextLite(
OUT PtrUDFIrpContextLite *IrpContextLite,
IN PtrUDFIrpContext IrpContext,
IN PtrUDFFCB Fcb
)
{
PtrUDFIrpContextLite LocalIrpContextLite = (PtrUDFIrpContextLite)MyAllocatePool__(NonPagedPool,sizeof(UDFIrpContextLite));
if(!LocalIrpContextLite)
return STATUS_INSUFFICIENT_RESOURCES;
// Zero and then initialize the structure.
RtlZeroMemory( LocalIrpContextLite, sizeof( UDFIrpContextLite ));
LocalIrpContextLite->NodeIdentifier.NodeType = UDF_NODE_TYPE_IRP_CONTEXT_LITE;
LocalIrpContextLite->NodeIdentifier.NodeSize = sizeof(UDFIrpContextLite);
LocalIrpContextLite->Fcb = Fcb;
LocalIrpContextLite->TreeLength = IrpContext->TreeLength;
// Copy RealDevice for workque algorithms.
LocalIrpContextLite->RealDevice = IrpContext->TargetDeviceObject;
LocalIrpContextLite->IrpContextFlags = IrpContext->IrpContextFlags;
*IrpContextLite = LocalIrpContextLite;
return STATUS_SUCCESS;
} // end UDFInitializeIrpContextLite()
NTSTATUS
NTAPI
UDFQuerySetEA(
PDEVICE_OBJECT DeviceObject, // the logical volume device object
PIRP Irp // I/O Request Packet
)
{
NTSTATUS RC = STATUS_SUCCESS;
// PtrUDFIrpContext PtrIrpContext = NULL;
BOOLEAN AreWeTopLevel = FALSE;
UDFPrint(("UDFQuerySetEA: \n"));
FsRtlEnterFileSystem();
ASSERT(DeviceObject);
ASSERT(Irp);
// set the top level context
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
RC = STATUS_EAS_NOT_SUPPORTED;
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
if(AreWeTopLevel) {
IoSetTopLevelIrp(NULL);
}
FsRtlExitFileSystem();
return(RC);
} // end UDFQuerySetEA()
ULONG
UDFIsResourceAcquired(
IN PERESOURCE Resource
)
{
ULONG ReAcqRes =
ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
(ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
return ReAcqRes;
} // end UDFIsResourceAcquired()
BOOLEAN
UDFAcquireResourceExclusiveWithCheck(
IN PERESOURCE Resource
)
{
ULONG ReAcqRes =
ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
(ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
if(ReAcqRes) {
UDFPrint(("UDFAcquireResourceExclusiveWithCheck: ReAcqRes, %x\n", ReAcqRes));
} else {
// BrutePoint();
}
if(ReAcqRes == 1) {
// OK
} else
if(ReAcqRes == 2) {
UDFPrint(("UDFAcquireResourceExclusiveWithCheck: !!! Shared !!!\n"));
//BrutePoint();
} else {
UDFAcquireResourceExclusive(Resource, TRUE);
return TRUE;
}
return FALSE;
} // end UDFAcquireResourceExclusiveWithCheck()
BOOLEAN
UDFAcquireResourceSharedWithCheck(
IN PERESOURCE Resource
)
{
ULONG ReAcqRes =
ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
(ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
if(ReAcqRes) {
UDFPrint(("UDFAcquireResourceSharedWithCheck: ReAcqRes, %x\n", ReAcqRes));
/* } else {
BrutePoint();*/
}
if(ReAcqRes == 2) {
// OK
} else
if(ReAcqRes == 1) {
UDFPrint(("UDFAcquireResourceSharedWithCheck: Exclusive\n"));
//BrutePoint();
} else {
UDFAcquireResourceShared(Resource, TRUE);
return TRUE;
}
return FALSE;
} // end UDFAcquireResourceSharedWithCheck()
NTSTATUS
UDFWCacheErrorHandler(
IN PVOID Context,
IN PWCACHE_ERROR_CONTEXT ErrorInfo
)
{
InterlockedIncrement((PLONG)&(((PVCB)Context)->IoErrorCounter));
return ErrorInfo->Status;
}
#include "Include/misc_common.cpp"
#include "Include/regtools.cpp"