reactos/drivers/filesystems/udfs/fscntrl.cpp

2616 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.
////////////////////////////////////////////////////////////////////
/*
Module Name: FsCntrl.cpp
Abstract:
Contains code to handle the "File System IOCTL" dispatch entry point.
Environment:
Kernel mode only
*/
#include "udffs.h"
// define the file specific bug-check id
#define UDF_BUG_CHECK_ID UDF_FILE_FS_CONTROL
NTSTATUS UDFBlankMount(IN PVCB Vcb);
PDIR_INDEX_HDR UDFDirIndexAlloc(IN uint_di i);
/*
Function: UDFFSControl()
Description:
The I/O Manager will invoke this routine to handle a File System
Control request (this is IRP_MJ_FILE_SYSTEM_CONTROL dispatch point)
*/
NTSTATUS
NTAPI
UDFFSControl(
PDEVICE_OBJECT DeviceObject, // the logical volume device object
PIRP Irp // I/O Request Packet
)
{
NTSTATUS RC = STATUS_SUCCESS;
PtrUDFIrpContext PtrIrpContext;
BOOLEAN AreWeTopLevel = FALSE;
UDFPrint(("\nUDFFSControl: \n\n"));
FsRtlEnterFileSystem();
ASSERT(DeviceObject);
ASSERT(Irp);
// set the top level context
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
_SEH2_TRY {
// get an IRP context structure and issue the request
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
if(PtrIrpContext) {
RC = UDFCommonFSControl(PtrIrpContext, Irp);
} else {
RC = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
UDFPrintErr(("UDFFSControl: exception ***"));
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
} _SEH2_END;
if(AreWeTopLevel) {
IoSetTopLevelIrp(NULL);
}
FsRtlExitFileSystem();
return(RC);
} // end UDFFSControl()
/*
Function: UDFCommonFSControl()
Description:
The actual work is performed here.
Expected Interrupt Level (for execution) :
IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
to be deferred to a worker thread context)
Return Value: STATUS_SUCCESS/Error
*/
NTSTATUS
NTAPI
UDFCommonFSControl(
PtrUDFIrpContext PtrIrpContext,
PIRP Irp // I/O Request Packet
)
{
NTSTATUS RC = STATUS_UNRECOGNIZED_VOLUME;
PIO_STACK_LOCATION IrpSp = NULL;
// PDEVICE_OBJECT PtrTargetDeviceObject = NULL;
UDFPrint(("\nUDFCommonFSControl\n\n"));
// BrutePoint();
_SEH2_TRY {
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IrpSp);
switch ((IrpSp)->MinorFunction)
{
case IRP_MN_USER_FS_REQUEST:
UDFPrint((" UDFFSControl: UserFsReq request ....\n"));
RC = UDFUserFsCtrlRequest(PtrIrpContext,Irp);
break;
case IRP_MN_MOUNT_VOLUME:
UDFPrint((" UDFFSControl: MOUNT_VOLUME request ....\n"));
RC = UDFMountVolume(PtrIrpContext,Irp);
break;
case IRP_MN_VERIFY_VOLUME:
UDFPrint((" UDFFSControl: VERIFY_VOLUME request ....\n"));
RC = UDFVerifyVolume(Irp);
break;
default:
UDFPrintErr((" UDFFSControl: STATUS_INVALID_DEVICE_REQUEST MinorFunction %x\n", (IrpSp)->MinorFunction));
RC = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
break;
}
//try_exit: NOTHING;
} _SEH2_FINALLY {
if (!_SEH2_AbnormalTermination()) {
// Free up the Irp Context
UDFPrint((" UDFCommonFSControl: finally\n"));
UDFReleaseIrpContext(PtrIrpContext);
} else {
UDFPrint((" UDFCommonFSControl: finally after exception ***\n"));
}
} _SEH2_END;
return(RC);
} // end UDFCommonFSControl()
/*
Routine Description:
This is the common routine for implementing the user's requests made
through NtFsControlFile.
Arguments:
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
NTAPI
UDFUserFsCtrlRequest(
PtrUDFIrpContext IrpContext,
PIRP Irp
)
{
NTSTATUS RC;
PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation( Irp );
// Case on the control code.
switch ( IrpSp->Parameters.FileSystemControl.FsControlCode ) {
case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
case FSCTL_REQUEST_BATCH_OPLOCK :
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE :
case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
case FSCTL_OPLOCK_BREAK_NOTIFY :
case FSCTL_OPLOCK_BREAK_ACK_NO_2 :
case FSCTL_REQUEST_FILTER_OPLOCK :
UDFPrint(("UDFUserFsCtrlRequest: OPLOCKS\n"));
RC = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
/*
RC = UDFOplockRequest( IrpContext, Irp );
break;
*/
case FSCTL_INVALIDATE_VOLUMES :
RC = UDFInvalidateVolumes( IrpContext, Irp );
break;
/*
case FSCTL_MOVE_FILE:
case FSCTL_QUERY_ALLOCATED_RANGES:
case FSCTL_SET_ZERO_DATA:
case FSCTL_SET_SPARSE:
case FSCTL_MARK_VOLUME_DIRTY:
RC = UDFDirtyVolume( IrpContext, Irp );
break;
*/
case FSCTL_IS_VOLUME_DIRTY:
RC = UDFIsVolumeDirty(IrpContext, Irp);
break;
case FSCTL_ALLOW_EXTENDED_DASD_IO:
UDFPrint(("UDFUserFsCtrlRequest: FSCTL_ALLOW_EXTENDED_DASD_IO\n"));
// DASD i/o is always permitted
// So, no-op this call
RC = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case FSCTL_DISMOUNT_VOLUME:
RC = UDFDismountVolume( IrpContext, Irp );
break;
case FSCTL_IS_VOLUME_MOUNTED:
RC = UDFIsVolumeMounted( IrpContext, Irp );
break;
case FSCTL_FILESYSTEM_GET_STATISTICS:
RC = UDFGetStatistics( IrpContext, Irp );
break;
case FSCTL_LOCK_VOLUME:
RC = UDFLockVolume( IrpContext, Irp );
break;
case FSCTL_UNLOCK_VOLUME:
RC = UDFUnlockVolume( IrpContext, Irp );
break;
case FSCTL_IS_PATHNAME_VALID:
RC = UDFIsPathnameValid( IrpContext, Irp );
break;
case FSCTL_GET_VOLUME_BITMAP:
UDFPrint(("UDFUserFsCtrlRequest: FSCTL_GET_VOLUME_BITMAP\n"));
RC = UDFGetVolumeBitmap( IrpContext, Irp );
break;
case FSCTL_GET_RETRIEVAL_POINTERS:
UDFPrint(("UDFUserFsCtrlRequest: FSCTL_GET_RETRIEVAL_POINTERS\n"));
RC = UDFGetRetrievalPointers( IrpContext, Irp, 0 );
break;
// We don't support any of the known or unknown requests.
default:
UDFPrintErr(("UDFUserFsCtrlRequest: STATUS_INVALID_DEVICE_REQUEST for %x\n",
IrpSp->Parameters.FileSystemControl.FsControlCode));
RC = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
IoCompleteRequest(Irp,IO_DISK_INCREMENT);
return RC;
} // end UDFUserFsCtrlRequest()
/*
Routine Description:
This is the common routine for implementing the mount requests
Arguments:
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
NTAPI
UDFMountVolume(
IN PtrUDFIrpContext PtrIrpContext,
IN PIRP Irp
)
{
NTSTATUS RC;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_OBJECT TargetDeviceObject = NULL;
PFILTER_DEV_EXTENSION filterDevExt;
PDEVICE_OBJECT fsDeviceObject;
PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb;
PVCB Vcb = NULL;
// PVCB OldVcb = NULL;
PDEVICE_OBJECT VolDo = NULL;
IO_STATUS_BLOCK Iosb;
ULONG MediaChangeCount = 0;
ULONG Characteristics;
DEVICE_TYPE FsDeviceType;
BOOLEAN RestoreDoVerify = FALSE;
BOOLEAN WrongMedia = FALSE;
BOOLEAN RemovableMedia = TRUE;
BOOLEAN CompleteIrp = FALSE;
ULONG Mode;
TEST_UNIT_READY_USER_OUT TestUnitReadyBuffer;
ULONG i;
LARGE_INTEGER delay;
BOOLEAN VcbAcquired = FALSE;
BOOLEAN DeviceNotTouched = TRUE;
BOOLEAN Locked = FALSE;
int8* ioBuf = NULL;
ASSERT(IrpSp);
UDFPrint(("\n !!! UDFMountVolume\n"));
// UDFPrint(("Build " VER_STR_PRODUCT "\n\n"));
fsDeviceObject = PtrIrpContext->TargetDeviceObject;
UDFPrint(("Mount on device object %x\n", fsDeviceObject));
filterDevExt = (PFILTER_DEV_EXTENSION)fsDeviceObject->DeviceExtension;
if (filterDevExt->NodeIdentifier.NodeType == UDF_NODE_TYPE_FILTER_DEVOBJ &&
filterDevExt->NodeIdentifier.NodeSize == sizeof(FILTER_DEV_EXTENSION)) {
CompleteIrp = FALSE;
} else
if (filterDevExt->NodeIdentifier.NodeType == UDF_NODE_TYPE_UDFFS_DEVOBJ &&
filterDevExt->NodeIdentifier.NodeSize == sizeof(UDFFS_DEV_EXTENSION)) {
CompleteIrp = TRUE;
} else {
UDFPrintErr(("Invalid node type in FS or FILTER DeviceObject\n"));
ASSERT(FALSE);
}
// Get a pointer to the target physical/virtual device object.
TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
if(((Characteristics = TargetDeviceObject->Characteristics) & FILE_FLOPPY_DISKETTE) ||
(UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_BEING_UNLOADED) ) {
WrongMedia = TRUE;
} else {
RemovableMedia = (Characteristics & FILE_REMOVABLE_MEDIA) ? TRUE : FALSE;
if(TargetDeviceObject->DeviceType != FILE_DEVICE_CD_ROM) {
if(UDFGetRegParameter(NULL, REG_MOUNT_ON_CDONLY_NAME, TRUE)) {
WrongMedia = TRUE;
}
}
if(TargetDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) {
FsDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
#ifdef UDF_HDD_SUPPORT
} else
if (TargetDeviceObject->DeviceType == FILE_DEVICE_DISK) {
if(RemovableMedia) {
if(!UDFGetRegParameter(NULL, REG_MOUNT_ON_ZIP_NAME, FALSE)) {
WrongMedia = TRUE;
}
} else {
if(!UDFGetRegParameter(NULL, REG_MOUNT_ON_HDD_NAME, FALSE)) {
WrongMedia = TRUE;
}
}
FsDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
#endif //UDF_HDD_SUPPORT
} else {
WrongMedia = TRUE;
}
}
// Acquire GlobalDataResource
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
_SEH2_TRY {
UDFScanForDismountedVcb(PtrIrpContext);
if(WrongMedia) try_return(RC = STATUS_UNRECOGNIZED_VOLUME);
if(RemovableMedia) {
UDFPrint(("UDFMountVolume: removable media\n"));
// just remember current MediaChangeCount
// or fail if No Media ....
// experimental CHECK_VERIFY, for fucking BENQ DVD_DD_1620
// Now we can get device state via GET_EVENT (if supported)
// or still one TEST_UNIT_READY command
RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
TargetDeviceObject,
NULL,0,
&MediaChangeCount,sizeof(ULONG),
FALSE,&Iosb );
// Send TEST_UNIT_READY comment
// This can spin-up or wake-up the device
if(UDFGetRegParameter(NULL, UDF_WAIT_CD_SPINUP, TRUE)) {
delay.QuadPart = -15000000LL; // 1.5 sec
for(i=0; i<UDF_READY_MAX_RETRY; i++) {
// Use device default ready timeout
Mode = 0;
RC = UDFPhSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY,
TargetDeviceObject,
&Mode,sizeof(Mode),
&TestUnitReadyBuffer,sizeof(TEST_UNIT_READY_USER_OUT),
FALSE,NULL);
UDFPrint(("UDFMountVolume: TEST_UNIT_READY %x\n", RC));
if(!NT_SUCCESS(RC))
break;
if(TestUnitReadyBuffer.SenseKey == SCSI_SENSE_NOT_READY &&
TestUnitReadyBuffer.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY &&
TestUnitReadyBuffer.AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY) {
UDFPrint(("UDFMountVolume: retry\n"));
KeDelayExecutionThread(KernelMode, FALSE, &delay);
//delay.QuadPart -= 10000000LL; // 1.0 sec
} else {
break;
}
}
if(i) {
UDFPrint(("UDFMountVolume: additional delay 3 sec\n"));
delay.QuadPart = -30000000LL; // 3.0 sec
KeDelayExecutionThread(KernelMode, FALSE, &delay);
}
}
// Now we can get device state via GET_EVENT (if supported)
// or still one TEST_UNIT_READY command
RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
TargetDeviceObject,
NULL,0,
&MediaChangeCount,sizeof(ULONG),
FALSE,&Iosb );
if(RC == STATUS_IO_DEVICE_ERROR) {
UDFPrint(("UDFMountVolume: retry check verify\n"));
RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
TargetDeviceObject,
NULL,0,
&MediaChangeCount,sizeof(ULONG),
FALSE,&Iosb );
}
if(!NT_SUCCESS(RC) && (RC != STATUS_VERIFY_REQUIRED))
try_return(RC);
// Be safe about the count in case the driver didn't fill it in
if(Iosb.Information != sizeof(ULONG)) {
MediaChangeCount = 0;
}
if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
// Check if device is busy before locking tray and performing
// further geomentry discovery. This is needed to avoid streaming
// loss during CD-R recording. Note, that some recording tools
// work with device via SPTI bypassing FS/Device driver layers.
ioBuf = (int8*)MyAllocatePool__(NonPagedPool,4096);
if(!ioBuf) {
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
}
RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,TargetDeviceObject,
ioBuf,sizeof(DISK_GEOMETRY),
ioBuf,sizeof(DISK_GEOMETRY),
FALSE, NULL );
if(RC == STATUS_DEVICE_NOT_READY) {
// probably, the device is really busy, may be by CD/DVD recording
UserPrint((" busy (*)\n"));
try_return(RC);
}
}
// lock media for now
if(!WrongMedia) {
((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = TRUE;
RC = UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
TargetDeviceObject,
&MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
NULL,0,
FALSE,NULL);
Locked = TRUE;
}
}
// Now before we can initialize the Vcb we need to set up the
// Get our device object and alignment requirement.
// Device extension == VCB
UDFPrint(("UDFMountVolume: create device\n"));
RC = IoCreateDevice( UDFGlobalData.DriverObject,
sizeof(VCB),
NULL,
FsDeviceType,
0,
FALSE,
&VolDo );
if(!NT_SUCCESS(RC)) try_return(RC);
// Our alignment requirement is the larger of the processor alignment requirement
// already in the volume device object and that in the DeviceObjectWeTalkTo
if(TargetDeviceObject->AlignmentRequirement > VolDo->AlignmentRequirement) {
VolDo->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
}
VolDo->Flags &= ~DO_DEVICE_INITIALIZING;
// device object field in the VPB to point to our new volume device
// object.
Vpb->DeviceObject = (PDEVICE_OBJECT) VolDo;
// We must initialize the stack size in our device object before
// the following reads, because the I/O system has not done it yet.
((PDEVICE_OBJECT)VolDo)->StackSize = (CCHAR) (TargetDeviceObject->StackSize + 1);
Vcb = (PVCB)VolDo->DeviceExtension;
// Initialize the Vcb. This routine will raise on an allocation
// failure.
RC = UDFInitializeVCB(VolDo,TargetDeviceObject,Vpb);
if(!NT_SUCCESS(RC)) {
Vcb = NULL;
try_return(RC);
}
VolDo = NULL;
Vpb = NULL;
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
VcbAcquired = TRUE;
// Let's reference the Vpb to make sure we are the one to
// have the last dereference.
Vcb->Vpb->ReferenceCount ++;
Vcb->MediaChangeCount = MediaChangeCount;
Vcb->FsDeviceType = FsDeviceType;
// Clear the verify bit for the start of mount.
if(Vcb->Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) {
Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
RestoreDoVerify = TRUE;
}
DeviceNotTouched = FALSE;
RC = UDFGetDiskInfo(TargetDeviceObject,Vcb);
if(!NT_SUCCESS(RC)) try_return(RC);
// **** Read registry settings ****
UDFReadRegKeys(Vcb, FALSE, FALSE);
Vcb->MountPhErrorCount = 0;
// Initialize internal cache
Mode = WCACHE_MODE_ROM;
RC = WCacheInit__(&(Vcb->FastCache),
Vcb->WCacheMaxFrames,
Vcb->WCacheMaxBlocks,
Vcb->WriteBlockSize,
5, Vcb->BlockSizeBits,
Vcb->WCacheBlocksPerFrameSh,
0/*Vcb->FirstLBA*/, Vcb->LastPossibleLBA, Mode,
0/*WCACHE_CACHE_WHOLE_PACKET*/ |
(Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) |
(Vcb->CacheChainedIo ? WCACHE_CHAINED_IO : 0) |
WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS, // this will be cleared after mount
Vcb->WCacheFramesToKeepFree,
// UDFTWrite, UDFTRead,
UDFTWriteVerify, UDFTReadVerify,
#ifdef UDF_ASYNC_IO
UDFTWriteAsync, UDFTReadAsync,
#else //UDF_ASYNC_IO
NULL, NULL,
#endif //UDF_ASYNC_IO
UDFIsBlockAllocated,
UDFUpdateVAT,
UDFWCacheErrorHandler);
if(!NT_SUCCESS(RC)) try_return(RC);
RC = UDFVInit(Vcb);
if(!NT_SUCCESS(RC)) try_return(RC);
UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
RC = UDFGetDiskInfoAndVerify(TargetDeviceObject,Vcb);
UDFReleaseResource(&(Vcb->BitMapResource1));
ASSERT(!Vcb->Modified);
WCacheChFlags__(&(Vcb->FastCache),
WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet
WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS); // let user retry request on Bad Blocks
#ifdef UDF_READ_ONLY_BUILD
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY;
#endif //UDF_READ_ONLY_BUILD
if(!NT_SUCCESS(RC)) {
UDFPrint(("UDFMountVolume: try raw mount\n"));
if(Vcb->NSRDesc & VRS_ISO9660_FOUND) {
UDFPrint(("UDFMountVolume: block raw mount due to ISO9660 presence\n"));
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
try_return(RC);
}
try_raw_mount:
UDFPrint(("UDFMountVolume: try raw mount (2)\n"));
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
UDFPrint(("UDFMountVolume: trying raw mount...\n"));
Vcb->VolIdent.Length =
(Vcb->VolIdent.MaximumLength = sizeof(UDF_BLANK_VOLUME_LABEL)) - 2;
if(Vcb->VolIdent.Buffer)
MyFreePool__(Vcb->VolIdent.Buffer);
Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(UDF_BLANK_VOLUME_LABEL));
if(!Vcb->VolIdent.Buffer)
try_return(STATUS_INSUFFICIENT_RESOURCES);
RtlCopyMemory(Vcb->VolIdent.Buffer, UDF_BLANK_VOLUME_LABEL, sizeof(UDF_BLANK_VOLUME_LABEL));
RC = UDFBlankMount(Vcb);
if(!NT_SUCCESS(RC)) try_return(RC);
} else {
// Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
try_return(RC);
}
} else {
Vcb->MountPhErrorCount = -1;
#ifndef UDF_READ_ONLY_BUILD
// set cache mode according to media type
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) {
UDFPrint(("UDFMountVolume: writable volume\n"));
if(!Vcb->CDR_Mode) {
if((FsDeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
CdrwMediaClassEx_IsRAM(Vcb->MediaClassEx)) {
UDFPrint(("UDFMountVolume: RAM mode\n"));
Mode = WCACHE_MODE_RAM;
} else {
UDFPrint(("UDFMountVolume: RW mode\n"));
Mode = WCACHE_MODE_RW;
}
/* if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
} else {
Vcb->WriteSecurity = TRUE;
}*/
} else {
UDFPrint(("UDFMountVolume: R mode\n"));
Mode = WCACHE_MODE_R;
}
// we can't record ACL on old format disks
if(!UDFNtAclSupported(Vcb)) {
UDFPrint(("UDFMountVolume: NO ACL and ExtFE support\n"));
Vcb->WriteSecurity = FALSE;
Vcb->UseExtendedFE = FALSE;
}
}
WCacheSetMode__(&(Vcb->FastCache), Mode);
#endif //UDF_READ_ONLY_BUILD
// Complete mount operations: create root FCB
UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
RC = UDFCompleteMount(Vcb);
UDFReleaseResource(&(Vcb->BitMapResource1));
if(!NT_SUCCESS(RC)) {
// We must have Vcb->VCBOpenCount = 1 for UDFBlankMount()
// Thus, we should not decrement it here
// Also, if we shall not perform BlankMount,
// but simply cleanup and return error, Vcb->VCBOpenCount
// will be decremented during cleanup. Thus anyway it must
// stay 1 unchanged here
//UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
UDFCloseResidual(Vcb);
Vcb->VCBOpenCount = 1;
if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)
Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
goto try_raw_mount;
}
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK;
}
#ifndef UDF_READ_ONLY_BUILD
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) {
RC = UDFStartEjectWaiter(Vcb);
if(!NT_SUCCESS(RC)) try_return(RC);
} else {
UDFPrint(("UDFMountVolume: RO mount\n"));
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
}
#endif //UDF_READ_ONLY_BUILD
Vcb->Vpb->SerialNumber = Vcb->PhSerialNumber;
Vcb->Vpb->VolumeLabelLength = Vcb->VolIdent.Length;
RtlCopyMemory( Vcb->Vpb->VolumeLabel,
Vcb->VolIdent.Buffer,
Vcb->VolIdent.Length );
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED;
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
Vcb->TotalAllocUnits = UDFGetTotalSpace(Vcb);
Vcb->FreeAllocUnits = UDFGetFreeSpace(Vcb);
// Register shutdown routine
if(!Vcb->ShutdownRegistered) {
UDFPrint(("UDFMountVolume: Register shutdown routine\n"));
IoRegisterShutdownNotification(Vcb->VCBDeviceObject);
Vcb->ShutdownRegistered = TRUE;
}
// unlock media
if(RemovableMedia) {
if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) {
UDFPrint(("UDFMountVolume: unlock media on RO volume\n"));
((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = FALSE;
UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
TargetDeviceObject,
&MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
NULL,0,
FALSE,NULL);
if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)
UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
}
}
if (UDFGlobalData.MountEvent)
{
Vcb->IsVolumeJustMounted = TRUE;
KeSetEvent(UDFGlobalData.MountEvent, 0, FALSE);
}
// The new mount is complete.
UDFReleaseResource( &(Vcb->VCBResource) );
VcbAcquired = FALSE;
Vcb = NULL;
RC = STATUS_SUCCESS;
try_exit: NOTHING;
} _SEH2_FINALLY {
UDFPrint(("UDFMountVolume: RC = %x\n", RC));
if(ioBuf) {
MyFreePool__(ioBuf);
}
if(!NT_SUCCESS(RC)) {
if(RemovableMedia && Locked) {
UDFPrint(("UDFMountVolume: unlock media\n"));
((PPREVENT_MEDIA_REMOVAL_USER_IN)(&MediaChangeCount))->PreventMediaRemoval = FALSE;
UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
TargetDeviceObject,
&MediaChangeCount,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
NULL,0,
FALSE,NULL);
}
/* if((RC != STATUS_DEVICE_NOT_READY) &&
(RC != STATUS_NO_MEDIA_IN_DEVICE) ) {*/
// reset driver
if(!DeviceNotTouched &&
(!Vcb || (Vcb && (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)))) {
UDFPrint(("UDFMountVolume: reset driver\n"));
UDFResetDeviceDriver(Vcb, TargetDeviceObject, TRUE);
}
if(RC == STATUS_CRC_ERROR || RC == STATUS_FILE_CORRUPT_ERROR) {
UDFPrint(("UDFMountVolume: status -> STATUS_UNRECOGNIZED_VOLUME\n"));
RC = STATUS_UNRECOGNIZED_VOLUME;
}
// If we didn't complete the mount then cleanup any remaining structures.
if(Vpb) {
Vpb->DeviceObject = NULL;
}
if(Vcb) {
// Restore the verify bit.
if(RestoreDoVerify) {
Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
}
// Make sure there is no Vcb since it could go away
if(Vcb->VCBOpenCount)
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
// This procedure will also delete the volume device object
if(UDFDismountVcb( Vcb, VcbAcquired )) {
UDFReleaseResource( &(Vcb->VCBResource) );
}
} else if(VolDo) {
IoDeleteDevice( VolDo );
}
}
// Release the global resource.
UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
if (CompleteIrp || NT_SUCCESS(RC)) {
if(!_SEH2_AbnormalTermination()) {
// Set mount event
UDFPrint(("UDFMountVolume: complete req RC %x\n", RC));
UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_MOUNT);
// Complete the IRP.
Irp->IoStatus.Status = RC;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
} else {
// Pass Irp to lower driver (CDFS)
// Get this driver out of the driver stack and get to the next driver as
// quickly as possible.
Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;
// Now call the appropriate file system driver with the request.
RC = IoCallDriver( filterDevExt->lowerFSDeviceObject, Irp );
}
} _SEH2_END;
UDFPrint(("UDFMountVolume: final RC = %x\n", RC));
return RC;
} // end UDFMountVolume()
NTSTATUS
UDFStartEjectWaiter(
IN PVCB Vcb
)
{
// NTSTATUS RC;
PREVENT_MEDIA_REMOVAL_USER_IN Buff;
UDFPrint(("UDFStartEjectWaiter:\n"));
if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) {
UDFPrint((" UDF_VCB_FLAGS_MEDIA_READ_ONLY\n"));
}
if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) {
UDFPrint((" UDF_VCB_FLAGS_MEDIA_LOCKED\n"));
}
UDFPrint((" EjectWaiter=%x\n", Vcb->EjectWaiter));
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) &&
/*!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) &&*/
!(Vcb->EjectWaiter)) {
UDFPrint(("UDFStartEjectWaiter: check driver\n"));
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) &&
(Vcb->FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM)) {
// we don't know how to write without our device driver
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
UDFPrint((" not our driver, ignore\n"));
return STATUS_SUCCESS;
}
UDFPrint(("UDFStartEjectWaiter: check removable\n"));
if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) {
// prevent media removal
UDFPrint(("UDFStartEjectWaiter: lock media\n"));
Buff.PreventMediaRemoval = TRUE;
UDFTSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
Vcb,
&Buff,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
NULL,0,
FALSE,NULL );
Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_LOCKED;
}
UDFPrint(("UDFStartEjectWaiter: prepare to start\n"));
// initialize Eject Request waiter
Vcb->EjectWaiter = (PUDFEjectWaitContext)MyAllocatePool__(NonPagedPool, sizeof(UDFEjectWaitContext));
if(!(Vcb->EjectWaiter)) return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeEvent(&(Vcb->WaiterStopped), NotificationEvent, FALSE);
Vcb->EjectWaiter->Vcb = Vcb;
Vcb->EjectWaiter->SoftEjectReq = FALSE;
KeInitializeEvent(&(Vcb->EjectWaiter->StopReq), NotificationEvent, FALSE);
// Vcb->EjectWaiter->StopReq = FALSE;
Vcb->EjectWaiter->WaiterStopped = &(Vcb->WaiterStopped);
// This can occure after unexpected media loss, when EjectRequestWaiter
// terminates automatically
ASSERT(!(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT));
Vcb->VCBFlags |= UDF_VCB_FLAGS_STOP_WAITER_EVENT;
ExInitializeWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), UDFEjectReqWaiter, Vcb->EjectWaiter);
UDFPrint(("UDFStartEjectWaiter: create thread\n"));
ExQueueWorkItem(&(Vcb->EjectWaiter->EjectReqWorkQueueItem), DelayedWorkQueue);
} else {
UDFPrint((" ignore\n"));
}
return STATUS_SUCCESS;
} // end UDFStartEjectWaiter()
NTSTATUS
UDFCompleteMount(
IN PVCB Vcb
)
{
NTSTATUS RC;// = STATUS_SUCCESS;
PtrUDFNTRequiredFCB NtReqFcb = NULL;
PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL;
UNICODE_STRING LocalPath;
PtrUDFObjectName RootName;
PtrUDFFCB RootFcb;
UDFPrint(("UDFCompleteMount:\n"));
Vcb->ZBuffer = (PCHAR)DbgAllocatePoolWithTag(NonPagedPool, max(Vcb->LBlockSize, PAGE_SIZE), 'zNWD');
if(!Vcb->ZBuffer) return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(Vcb->ZBuffer, Vcb->LBlockSize);
UDFPrint(("UDFCompleteMount: alloc Root FCB\n"));
// Create the root index and reference it in the Vcb.
RootFcb =
Vcb->RootDirFCB = UDFAllocateFCB();
if(!RootFcb) return STATUS_INSUFFICIENT_RESOURCES;
UDFPrint(("UDFCompleteMount: alloc Root ObjName\n"));
// Allocate and set root FCB unique name
RootName = UDFAllocateObjectName();
if(!RootName) {
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
RC = MyInitUnicodeString(&(RootName->ObjectName),UDF_ROOTDIR_NAME);
if(!NT_SUCCESS(RC))
goto insuf_res_1;
RootFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO));
if(!RootFcb->FileInfo) {
RC = STATUS_INSUFFICIENT_RESOURCES;
insuf_res_1:
MyFreePool__(RootName->ObjectName.Buffer);
UDFReleaseObjectName(RootName);
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return RC;
}
UDFPrint(("UDFCompleteMount: open Root Dir\n"));
// Open Root Directory
RC = UDFOpenRootFile__( Vcb, &(Vcb->RootLbAddr), RootFcb->FileInfo );
if(!NT_SUCCESS(RC)) {
insuf_res_2:
UDFCleanUpFile__(Vcb, RootFcb->FileInfo);
MyFreePool__(RootFcb->FileInfo);
goto insuf_res_1;
}
RootFcb->FileInfo->Fcb = RootFcb;
if(!(RootFcb->NTRequiredFCB = RootFcb->FileInfo->Dloc->CommonFcb)) {
UDFPrint(("UDFCompleteMount: alloc Root ObjName (2)\n"));
if(!(RootFcb->NTRequiredFCB =
(PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) {
RC = STATUS_INSUFFICIENT_RESOURCES;
goto insuf_res_2;
}
RtlZeroMemory(RootFcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
RootFcb->FileInfo->Dloc->CommonFcb = RootFcb->NTRequiredFCB;
}
UDFPrint(("UDFCompleteMount: init FCB\n"));
RC = UDFInitializeFCB(RootFcb,Vcb,RootName,UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY,NULL);
if(!NT_SUCCESS(RC)) {
// if we get here, no resources are inited
RootFcb->OpenHandleCount =
RootFcb->ReferenceCount =
RootFcb->NTRequiredFCB->CommonRefCount = 0;
UDFCleanUpFile__(Vcb, RootFcb->FileInfo);
MyFreePool__(RootFcb->FileInfo);
MyFreePool__(RootFcb->NTRequiredFCB);
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return RC;
}
// this is a part of UDF_RESIDUAL_REFERENCE
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
RootFcb->OpenHandleCount =
RootFcb->ReferenceCount =
RootFcb->NTRequiredFCB->CommonRefCount = 1;
UDFGetFileXTime(RootFcb->FileInfo,
&(RootFcb->NTRequiredFCB->CreationTime.QuadPart),
&(RootFcb->NTRequiredFCB->LastAccessTime.QuadPart),
&(RootFcb->NTRequiredFCB->ChangeTime.QuadPart),
&(RootFcb->NTRequiredFCB->LastWriteTime.QuadPart) );
if(Vcb->SysStreamLbAddr.logicalBlockNum) {
Vcb->SysSDirFileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO));
if(!Vcb->SysSDirFileInfo) {
RC = STATUS_INSUFFICIENT_RESOURCES;
goto unwind_1;
}
// Open System SDir Directory
RC = UDFOpenRootFile__( Vcb, &(Vcb->SysStreamLbAddr), Vcb->SysSDirFileInfo );
if(!NT_SUCCESS(RC)) {
UDFCleanUpFile__(Vcb, Vcb->SysSDirFileInfo);
MyFreePool__(Vcb->SysSDirFileInfo);
Vcb->SysSDirFileInfo = NULL;
goto unwind_1;
} else {
Vcb->SysSDirFileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY;
}
}
// Open Unallocatable space stream
// Generally, it should be placed in SystemStreamDirectory, but some
// stupid apps think that RootDirectory is much better place.... :((
RC = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE);
if(NT_SUCCESS(RC)) {
RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL);
MyFreePool__(LocalPath.Buffer);
}
if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
//unwind_2:
UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo);
Vcb->NonAllocFileInfo = NULL;
// this was a part of UDF_RESIDUAL_REFERENCE
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
unwind_1:
// UDFCloseResidual() will clean up everything
return RC;
}
/* process Non-allocatable */
if(NT_SUCCESS(RC)) {
UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used
UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
} else {
/* try to read Non-allocatable from alternate locations */
RC = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE_2);
if(!NT_SUCCESS(RC)) {
goto unwind_1;
}
RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL);
MyFreePool__(LocalPath.Buffer);
if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
goto unwind_1;
}
if(NT_SUCCESS(RC)) {
UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used
UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
} else
if(Vcb->SysSDirFileInfo) {
RC = MyInitUnicodeString(&LocalPath, UDF_SN_NON_ALLOCATABLE);
if(!NT_SUCCESS(RC)) {
goto unwind_1;
}
RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->NonAllocFileInfo), NULL);
MyFreePool__(LocalPath.Buffer);
if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
goto unwind_1;
}
if(NT_SUCCESS(RC)) {
UDFMarkSpaceAsXXX(Vcb, Vcb->NonAllocFileInfo->Dloc, Vcb->NonAllocFileInfo->Dloc->DataLoc.Mapping, AS_USED); // used
// UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
} else {
RC = STATUS_SUCCESS;
}
} else {
RC = STATUS_SUCCESS;
}
}
/* Read SN UID mapping */
if(Vcb->SysSDirFileInfo) {
RC = MyInitUnicodeString(&LocalPath, UDF_SN_UID_MAPPING);
if(!NT_SUCCESS(RC))
goto unwind_3;
RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->UniqueIDMapFileInfo), NULL);
MyFreePool__(LocalPath.Buffer);
if(!NT_SUCCESS(RC) && (RC != STATUS_OBJECT_NAME_NOT_FOUND)) {
unwind_3:
// UDFCloseFile__(Vcb, Vcb->NonAllocFileInfo);
// UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo);
// if(Vcb->NonAllocFileInfo)
// MyFreePool__(Vcb->NonAllocFileInfo);
// Vcb->NonAllocFileInfo = NULL;
goto unwind_1;
} else {
Vcb->UniqueIDMapFileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY;
}
RC = STATUS_SUCCESS;
}
#define DWN_MAX_CFG_FILE_SIZE 0x10000
/* Read DWN config file from disk with disk-specific options */
RC = MyInitUnicodeString(&LocalPath, UDF_CONFIG_STREAM_NAME_W);
if(NT_SUCCESS(RC)) {
int8* buff;
uint32 len;
PUDF_FILE_INFO CfgFileInfo = NULL;
RC = UDFOpenFile__(Vcb, FALSE, TRUE, &LocalPath, RootFcb->FileInfo, &CfgFileInfo, NULL);
if(OS_SUCCESS(RC)) {
len = (ULONG)UDFGetFileSize(CfgFileInfo);
if(len && len < DWN_MAX_CFG_FILE_SIZE) {
buff = (int8*)MyAllocatePool__(NonPagedPool, len);
if(buff) {
RC = UDFReadFile__(Vcb, CfgFileInfo, 0, len, FALSE, buff, &len);
if(OS_SUCCESS(RC)) {
// parse config
Vcb->Cfg = (PUCHAR)buff;
Vcb->CfgLength = len;
UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE /*cfg*/);
Vcb->Cfg = NULL;
Vcb->CfgLength = 0;
Vcb->CfgVersion = 0;
}
MyFreePool__(buff);
}
}
UDFCloseFile__(Vcb, CfgFileInfo);
}
if(CfgFileInfo) {
UDFCleanUpFile__(Vcb, CfgFileInfo);
}
MyFreePool__(LocalPath.Buffer);
}
RC = STATUS_SUCCESS;
// clear Modified flags. It was not real modify, just
// bitmap construction
Vcb->BitmapModified = FALSE;
//Vcb->Modified = FALSE;
UDFPreClrModified(Vcb);
UDFClrModified(Vcb);
// this is a part of UDF_RESIDUAL_REFERENCE
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
NtReqFcb = RootFcb->NTRequiredFCB;
// Start initializing the fields contained in the CommonFCBHeader.
PtrCommonFCBHeader = &(NtReqFcb->CommonFCBHeader);
// DisAllow fast-IO for now.
// PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible;
PtrCommonFCBHeader->IsFastIoPossible = FastIoIsPossible;
// Initialize the MainResource and PagingIoResource pointers in
// the CommonFCBHeader structure to point to the ERESOURCE structures we
// have allocated and already initialized above.
// PtrCommonFCBHeader->Resource = &(NtReqFcb->MainResource);
// PtrCommonFCBHeader->PagingIoResource = &(NtReqFcb->PagingIoResource);
// Initialize the file size values here.
PtrCommonFCBHeader->AllocationSize.QuadPart = 0;
PtrCommonFCBHeader->FileSize.QuadPart = 0;
// The following will disable ValidDataLength support.
// PtrCommonFCBHeader->ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFI64;
PtrCommonFCBHeader->ValidDataLength.QuadPart = 0;
if(!NT_SUCCESS(RC))
return RC;
UDFAssignAcl(Vcb, NULL, RootFcb, NtReqFcb);
/*
Vcb->CDBurnerVolumeValid = true;
len =
Vcb->CDBurnerVolume.Length = 256;
Vcb->CDBurnerVolume.MaximumLength = 256;
Vcb->CDBurnerVolume.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, 256);
RC = RegTGetStringValue(NULL, REG_CD_BURNER_KEY_NAME, REG_CD_BURNER_VOLUME_NAME, Vcb->CDBurnerVolume.Buffer,
len);
Vcb->CDBurnerVolume.Length = (USHORT)(wcslen(Vcb->CDBurnerVolume.Buffer)*sizeof(WCHAR));
if(RC != STATUS_OBJECT_NAME_NOT_FOUND && !NT_SUCCESS(RC) )
return RC;
if (NT_SUCCESS(RC)) {
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
REG_CD_BURNER_KEY_NAME, REG_CD_BURNER_VOLUME_NAME,
REG_SZ,L"",sizeof(L"")+1);
} else {
Vcb->CDBurnerVolumeValid = false;
RC = STATUS_SUCCESS;
}
*/
ASSERT(!Vcb->Modified);
return RC;
} // end UDFCompleteMount()
NTSTATUS
UDFBlankMount(
IN PVCB Vcb
)
{
NTSTATUS RC;// = STATUS_SUCCESS;
PtrUDFNTRequiredFCB NtReqFcb = NULL;
PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL;
PtrUDFObjectName RootName;
PtrUDFFCB RootFcb;
PDIR_INDEX_HDR hDirNdx;
PDIR_INDEX_ITEM DirNdx;
// Create the root index and reference it in the Vcb.
RootFcb =
Vcb->RootDirFCB = UDFAllocateFCB();
if(!RootFcb) return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(RootFcb,sizeof(UDFFCB));
// Allocate and set root FCB unique name
RootName = UDFAllocateObjectName();
if(!RootName) {
//bl_unwind_2:
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
RC = MyInitUnicodeString(&(RootName->ObjectName),UDF_ROOTDIR_NAME);
if(!NT_SUCCESS(RC))
goto bl_unwind_1;
RootFcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB;
RootFcb->NodeIdentifier.NodeSize = sizeof(UDFFCB);
RootFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO));
if(!RootFcb->FileInfo) {
MyFreePool__(RootName->ObjectName.Buffer);
RC = STATUS_INSUFFICIENT_RESOURCES;
bl_unwind_1:
UDFReleaseObjectName(RootName);
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return RC;
}
RtlZeroMemory(RootFcb->FileInfo, sizeof(UDF_FILE_INFO));
if(!OS_SUCCESS(RC = UDFStoreDloc(Vcb, RootFcb->FileInfo, 1))) {
MyFreePool__(RootFcb->FileInfo);
RootFcb->FileInfo = NULL;
MyFreePool__(RootName->ObjectName.Buffer);
goto bl_unwind_1;
}
RootFcb->FileInfo->NextLinkedFile =
RootFcb->FileInfo->PrevLinkedFile = RootFcb->FileInfo;
hDirNdx = UDFDirIndexAlloc(2);
DirNdx = UDFDirIndex(hDirNdx,0);
DirNdx->FileCharacteristics = FILE_DIRECTORY;
DirNdx->FI_Flags = UDF_FI_FLAG_SYS_ATTR;
DirNdx->SysAttr = FILE_ATTRIBUTE_READONLY;
RtlInitUnicodeString(&DirNdx->FName, L".");
DirNdx->FileInfo = RootFcb->FileInfo;
DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL | HASH_KEEP_NAME);
DirNdx = UDFDirIndex(hDirNdx,1);
DirNdx->FI_Flags = UDF_FI_FLAG_SYS_ATTR;
if(Vcb->ShowBlankCd == 2) {
DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
}
DirNdx->SysAttr = FILE_ATTRIBUTE_READONLY;
RtlInitUnicodeString(&DirNdx->FName, L"Blank.CD");
DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
RootFcb->FileInfo->Dloc->DirIndex = hDirNdx;
RootFcb->FileInfo->Fcb = RootFcb;
if(!(RootFcb->NTRequiredFCB = RootFcb->FileInfo->Dloc->CommonFcb)) {
if(!(RootFcb->NTRequiredFCB =
(PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))) ) ) {
MyFreePool__(RootName->ObjectName.Buffer);
UDFReleaseObjectName(RootName);
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(RootFcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
RootFcb->FileInfo->Dloc->CommonFcb = RootFcb->NTRequiredFCB;
}
RC = UDFInitializeFCB(RootFcb,Vcb,RootName,UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY,NULL);
if(!NT_SUCCESS(RC)) {
// if we get here, no resources are inited
RootFcb->OpenHandleCount =
RootFcb->ReferenceCount =
RootFcb->NTRequiredFCB->CommonRefCount = 0;
UDFCleanUpFile__(Vcb, RootFcb->FileInfo);
MyFreePool__(RootFcb->FileInfo);
MyFreePool__(RootFcb->NTRequiredFCB);
UDFCleanUpFCB(RootFcb);
Vcb->RootDirFCB = NULL;
return RC;
}
// this is a part of UDF_RESIDUAL_REFERENCE
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
RootFcb->OpenHandleCount =
RootFcb->ReferenceCount =
RootFcb->NTRequiredFCB->CommonRefCount =
RootFcb->FileInfo->RefCount =
RootFcb->FileInfo->Dloc->LinkRefCount = 1;
// this is a part of UDF_RESIDUAL_REFERENCE
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
NtReqFcb = RootFcb->NTRequiredFCB;
// Start initializing the fields contained in the CommonFCBHeader.
PtrCommonFCBHeader = &(NtReqFcb->CommonFCBHeader);
// DisAllow fast-IO for now.
PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible;
// Initialize the MainResource and PagingIoResource pointers in
// the CommonFCBHeader structure to point to the ERESOURCE structures we
// have allocated and already initialized above.
PtrCommonFCBHeader->Resource = &(NtReqFcb->MainResource);
PtrCommonFCBHeader->PagingIoResource = &(NtReqFcb->PagingIoResource);
// Initialize the file size values here.
PtrCommonFCBHeader->AllocationSize.QuadPart = 0;
PtrCommonFCBHeader->FileSize.QuadPart = 0;
// The following will disable ValidDataLength support.
PtrCommonFCBHeader->ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFLL;
return RC;
} // end UDFBlankMount()
VOID
UDFCloseResidual(
IN PVCB Vcb
)
{
// Deinitialize Non-alloc file
if(Vcb->VCBOpenCount)
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
UDFPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo));
if(Vcb->NonAllocFileInfo) {
UDFCloseFile__(Vcb,Vcb->NonAllocFileInfo);
UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo);
MyFreePool__(Vcb->NonAllocFileInfo);
Vcb->NonAllocFileInfo = NULL;
}
// Deinitialize Unique ID Mapping
UDFPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo));
if(Vcb->UniqueIDMapFileInfo) {
UDFCloseFile__(Vcb,Vcb->UniqueIDMapFileInfo);
UDFCleanUpFile__(Vcb, Vcb->UniqueIDMapFileInfo);
MyFreePool__(Vcb->UniqueIDMapFileInfo);
Vcb->UniqueIDMapFileInfo = NULL;
}
// Deinitialize VAT file
UDFPrint(("UDFCloseResidual: VatFileInfo %x\n", Vcb->VatFileInfo));
if(Vcb->VatFileInfo) {
UDFCloseFile__(Vcb,Vcb->VatFileInfo);
UDFCleanUpFile__(Vcb, Vcb->VatFileInfo);
MyFreePool__(Vcb->VatFileInfo);
Vcb->VatFileInfo = NULL;
}
// System StreamDir
UDFPrint(("UDFCloseResidual: SysSDirFileInfo %x\n", Vcb->SysSDirFileInfo));
if(Vcb->SysSDirFileInfo) {
UDFCloseFile__(Vcb, Vcb->SysSDirFileInfo);
UDFCleanUpFile__(Vcb, Vcb->SysSDirFileInfo);
MyFreePool__(Vcb->SysSDirFileInfo);
Vcb->SysSDirFileInfo = NULL;
}
/* // Deinitialize root dir fcb
if(Vcb->RootDirFCB) {
UDFCloseFile__(Vcb,Vcb->RootDirFCB->FileInfo);
UDFCleanUpFile__(Vcb, Vcb->RootDirFCB->FileInfo);
MyFreePool__(Vcb->RootDirFCB->FileInfo);
UDFCleanUpFCB(Vcb->RootDirFCB);
// Remove root FCB reference in vcb
if(Vcb->VCBOpenCount) Vcb->VCBOpenCount--;
}
// Deinitialize Non-alloc file
if(Vcb->VCBOpenCount) Vcb->VCBOpenCount--;
if(Vcb->NonAllocFileInfo) {
UDFCloseFile__(Vcb,Vcb->NonAllocFileInfo);
// We must release VCB here !!!!
// UDFCleanUpFcbChain(Vcb, Vcb->NonAllocFileInfo, 1);
Vcb->NonAllocFileInfo = NULL;
}
// Deinitialize VAT file
if(Vcb->VatFileInfo) {
UDFCloseFile__(Vcb,Vcb->VatFileInfo);
// We must release VCB here !!!!
// UDFCleanUpFcbChain(Vcb, Vcb->VatFileInfo, 1);
Vcb->VatFileInfo = NULL;
}*/
// Deinitialize root dir fcb
UDFPrint(("UDFCloseResidual: RootDirFCB %x\n", Vcb->RootDirFCB));
if(Vcb->RootDirFCB) {
UDFCloseFile__(Vcb,Vcb->RootDirFCB->FileInfo);
if(Vcb->RootDirFCB->OpenHandleCount)
Vcb->RootDirFCB->OpenHandleCount--;
UDFCleanUpFcbChain(Vcb, Vcb->RootDirFCB->FileInfo, 1, TRUE);
// Remove root FCB reference in vcb
if(Vcb->VCBOpenCount)
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
Vcb->RootDirFCB = NULL;
}
} // end UDFCloseResidual()
VOID
UDFCleanupVCB(
IN PVCB Vcb
)
{
_SEH2_TRY {
UDFReleaseFileIdCache(Vcb);
UDFReleaseDlocList(Vcb);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
BrutePoint();
} _SEH2_END;
if(Vcb->ShutdownRegistered && Vcb->VCBDeviceObject) {
IoUnregisterShutdownNotification(Vcb->VCBDeviceObject);
Vcb->ShutdownRegistered = FALSE;
}
MyFreeMemoryAndPointer(Vcb->Partitions);
MyFreeMemoryAndPointer(Vcb->LVid);
MyFreeMemoryAndPointer(Vcb->Vat);
MyFreeMemoryAndPointer(Vcb->SparingTable);
if(Vcb->FSBM_Bitmap) {
DbgFreePool(Vcb->FSBM_Bitmap);
Vcb->FSBM_Bitmap = NULL;
}
if(Vcb->ZSBM_Bitmap) {
DbgFreePool(Vcb->ZSBM_Bitmap);
Vcb->ZSBM_Bitmap = NULL;
}
if(Vcb->BSBM_Bitmap) {
DbgFreePool(Vcb->BSBM_Bitmap);
Vcb->BSBM_Bitmap = NULL;
}
#ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS
if(Vcb->FSBM_Bitmap_owners) {
DbgFreePool(Vcb->FSBM_Bitmap_owners);
Vcb->FSBM_Bitmap_owners = NULL;
}
#endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS
if(Vcb->FSBM_OldBitmap) {
DbgFreePool(Vcb->FSBM_OldBitmap);
Vcb->FSBM_OldBitmap = NULL;
}
MyFreeMemoryAndPointer(Vcb->Statistics);
MyFreeMemoryAndPointer(Vcb->NTRequiredFCB);
MyFreeMemoryAndPointer(Vcb->VolIdent.Buffer);
MyFreeMemoryAndPointer(Vcb->TargetDevName.Buffer);
if(Vcb->ZBuffer) {
DbgFreePool(Vcb->ZBuffer);
Vcb->ZBuffer = NULL;
}
if(Vcb->fZBuffer) {
DbgFreePool(Vcb->fZBuffer);
Vcb->fZBuffer = NULL;
}
MyFreeMemoryAndPointer(Vcb->OPCh);
MyFreeMemoryAndPointer(Vcb->WParams);
MyFreeMemoryAndPointer(Vcb->Error);
MyFreeMemoryAndPointer(Vcb->TrackMap);
} // end UDFCleanupVCB()
/*
Routine Description:
This routine walks through the list of Vcb's looking for any which may
now be deleted. They may have been left on the list because there were
outstanding references.
Arguments:
Return Value:
None
*/
VOID
UDFScanForDismountedVcb(
IN PtrUDFIrpContext IrpContext
)
{
PVCB Vcb;
PLIST_ENTRY Link;
// Walk through all of the Vcb's attached to the global data.
Link = UDFGlobalData.VCBQueue.Flink;
while (Link != &(UDFGlobalData.VCBQueue)) {
Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
// Move to the next link now since the current Vcb may be deleted.
Link = Link->Flink;
// If dismount is already underway then check if this Vcb can
// go away.
if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) ||
((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) {
UDFCheckForDismount( IrpContext, Vcb, FALSE );
}
}
return;
} // end UDFScanForDismountedVcb()
/*
Routine Description:
This routine determines if a volume is currently mounted.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
UDFIsVolumeMounted(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
UDFPrint(("UDFIsVolumeMounted\n"));
Ccb = (PtrUDFCCB)IrpSp->FileObject->FsContext2;
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
if(Fcb &&
!(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
!(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) ) {
// Disable PopUps, we want to return any error.
IrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS;
// Verify the Vcb. This will raise in the error condition.
UDFVerifyVcb( IrpContext, Fcb->Vcb );
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
} // end UDFIsVolumeMounted()
/*
This routine returns the filesystem performance counters from the
appropriate VCB.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
UDFGetStatistics(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
NTSTATUS status;
PVCB Vcb;
PFILE_SYSTEM_STATISTICS Buffer;
ULONG BufferLength;
ULONG StatsSize;
ULONG BytesToCopy;
UDFPrint(("UDFGetStatistics\n"));
// Extract the buffer
BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
// Get a pointer to the output buffer.
Buffer = (PFILE_SYSTEM_STATISTICS)(Irp->AssociatedIrp.SystemBuffer);
// Make sure the buffer is big enough for at least the common part.
if (BufferLength < sizeof(FILESYSTEM_STATISTICS)) {
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
goto EO_stat;
}
// Now see how many bytes we can copy.
StatsSize = sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors;
if (BufferLength < StatsSize) {
BytesToCopy = BufferLength;
status = STATUS_BUFFER_OVERFLOW;
} else {
BytesToCopy = StatsSize;
status = STATUS_SUCCESS;
}
Vcb = (PVCB)(((PDEVICE_OBJECT)IrpSp->DeviceObject)->DeviceExtension);
// Fill in the output buffer
RtlCopyMemory( Buffer, Vcb->Statistics, BytesToCopy );
Irp->IoStatus.Information = BytesToCopy;
EO_stat:
Irp->IoStatus.Status = status;
return status;
} // end UDFGetStatistics()
/*
This routine determines if pathname is valid path for UDF Filesystem
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
UDFIsPathnameValid(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
PEXTENDED_IO_STACK_LOCATION IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
NTSTATUS RC;
PPATHNAME_BUFFER PathnameBuffer;
UNICODE_STRING PathName;
UNICODE_STRING CurName;
PWCHAR TmpBuffer;
UDFPrint(("UDFIsPathnameValid\n"));
// Extract the pathname
PathnameBuffer = (PPATHNAME_BUFFER)Irp->AssociatedIrp.SystemBuffer;
PathName.Buffer = PathnameBuffer->Name;
PathName.Length = (USHORT)PathnameBuffer->PathNameLength;
_SEH2_TRY {
// Check for an invalid buffer
if (FIELD_OFFSET(PATHNAME_BUFFER, Name[0]) + PathnameBuffer->PathNameLength >
IrpSp->Parameters.FileSystemControl.InputBufferLength) {
try_return( RC = STATUS_INVALID_PARAMETER);
}
while (TRUE) {
// get next path part...
TmpBuffer = PathName.Buffer;
PathName.Buffer = UDFDissectName(PathName.Buffer,&(CurName.Length) );
PathName.Length -= (USHORT)((ULONG)(PathName.Buffer) - (ULONG)TmpBuffer);
CurName.Buffer = PathName.Buffer - CurName.Length;
CurName.Length *= sizeof(WCHAR);
CurName.MaximumLength -= CurName.Length;
if (CurName.Length) {
// check path fragment size
if (CurName.Length > UDF_NAME_LEN*sizeof(WCHAR)) {
try_return(RC = STATUS_OBJECT_NAME_INVALID);
}
if (!UDFIsNameValid(&CurName, NULL, NULL)) {
try_return(RC = STATUS_OBJECT_NAME_INVALID);
}
} else {
try_return(RC = STATUS_SUCCESS);
}
}
try_exit: NOTHING;
} _SEH2_FINALLY {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = RC;
} _SEH2_END;
return RC;
} // end UDFIsPathnameValid()
/*
This routine performs the lock volume operation. It is responsible for
either completing of enqueuing the input Irp.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
UDFLockVolume(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp,
IN ULONG PID
)
{
NTSTATUS RC;
KIRQL SavedIrql;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
BOOLEAN VcbAcquired = FALSE;
UDFPrint(("UDFLockVolume: PID %x\n", PID));
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
// Check for volume open
if (Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_LOCK);
_SEH2_TRY {
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
#ifdef UDF_DELAYED_CLOSE
UDFCloseAllDelayed(Vcb);
#endif //UDF_DELAYED_CLOSE
// Acquire exclusive access to the Vcb.
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
VcbAcquired = TRUE;
// Verify the Vcb.
UDFVerifyVcb( IrpContext, Vcb );
// If the volume is already locked then complete with success if this file
// object has the volume locked, fail otherwise.
/* if (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) {
if (Vcb->VolumeLockFileObject == IrpSp->FileObject) {
RC = STATUS_SUCCESS;
} else {
RC = STATUS_ACCESS_DENIED;
}
// If the open count for the volume is greater than 1 then this request
// will fail.
} else if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE+1) {
RC = STATUS_ACCESS_DENIED;
// We will try to get rid of all of the user references. If there is only one
// remaining after the purge then we can allow the volume to be locked.
} else {
// flush system cache
UDFReleaseResource( &(Vcb->VCBResource) );
VcbAcquired = FALSE;
}*/
} _SEH2_FINALLY {
// Release the Vcb.
if(VcbAcquired) {
UDFReleaseResource( &(Vcb->VCBResource) );
VcbAcquired = FALSE;
}
} _SEH2_END;
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
VcbAcquired = TRUE;
UDFFlushLogicalVolume(NULL, NULL, Vcb/*, 0*/);
UDFReleaseResource( &(Vcb->VCBResource) );
VcbAcquired = FALSE;
// Check if the Vcb is already locked, or if the open file count
// is greater than 1 (which implies that someone else also is
// currently using the volume, or a file on the volume).
IoAcquireVpbSpinLock( &SavedIrql );
if (!(Vcb->Vpb->Flags & VPB_LOCKED) &&
(Vcb->VolumeLockPID == (ULONG)-1) &&
(Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE+1) &&
(Vcb->Vpb->ReferenceCount == 2)) {
// Mark volume as locked
if(PID == (ULONG)-1) {
Vcb->Vpb->Flags |= VPB_LOCKED;
}
Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED;
Vcb->VolumeLockFileObject = IrpSp->FileObject;
Vcb->VolumeLockPID = PID;
RC = STATUS_SUCCESS;
} else {
RC = STATUS_ACCESS_DENIED;
}
IoReleaseVpbSpinLock( SavedIrql );
if(!NT_SUCCESS(RC)) {
UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED);
}
// Complete the request if there haven't been any exceptions.
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = RC;
return RC;
} // end UDFLockVolume()
/*
This routine performs the unlock volume operation. It is responsible for
either completing of enqueuing the input Irp.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
UDFUnlockVolume(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp,
IN ULONG PID
)
{
NTSTATUS RC = STATUS_INVALID_PARAMETER;
KIRQL SavedIrql;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
UDFPrint(("UDFUnlockVolume: PID %x\n", PID));
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
// Check for volume open
if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
// Acquire exclusive access to the Vcb/Vpb.
IoAcquireVpbSpinLock( &SavedIrql );
_SEH2_TRY {
// We won't check for a valid Vcb for this request. An unlock will always
// succeed on a locked volume.
if(Vcb->Vpb->Flags & VPB_LOCKED ||
Vcb->VolumeLockPID == PID) {
Vcb->Vpb->Flags &= ~VPB_LOCKED;
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
Vcb->VolumeLockFileObject = NULL;
Vcb->VolumeLockPID = -1;
UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_UNLOCK);
RC = STATUS_SUCCESS;
} else {
RC = STATUS_NOT_LOCKED;
RC = STATUS_SUCCESS;
RC = STATUS_VOLUME_DISMOUNTED;
}
} _SEH2_FINALLY {
;
} _SEH2_END;
// Release all of our resources
IoReleaseVpbSpinLock( SavedIrql );
// Complete the request if there haven't been any exceptions.
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = RC;
return RC;
} // end UDFUnlockVolume()
/*
This routine performs the dismount volume operation. It is responsible for
either completing of enqueuing the input Irp. We only dismount a volume which
has been locked. The intent here is that someone has locked the volume (they are the
only remaining handle). We set the verify bit here and the user will close his handle.
We will dismount a volume with no user's handles in the verify path.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
*/
NTSTATUS
UDFDismountVolume(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
NTSTATUS RC;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
BOOLEAN VcbAcquired = FALSE;
UDFPrint(("\n ### UDFDismountVolume ###\n\n"));
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
// Check for volume open
if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT);
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK))
UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
#ifdef UDF_DELAYED_CLOSE
UDFCloseAllDelayed(Vcb);
#endif //UDF_DELAYED_CLOSE
// Acquire exclusive access to the Vcb.
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
VcbAcquired = TRUE;
_SEH2_TRY {
// Mark the volume as needs to be verified, but only do it if
// the vcb is locked by this handle and the volume is currently mounted.
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
// disable Eject Request Waiter if any
UDFReleaseResource( &(Vcb->VCBResource) );
VcbAcquired = FALSE;
UDFStopEjectWaiter(Vcb);
RC = STATUS_SUCCESS;
} else
if(/*!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) ||*/
!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) ||
(Vcb->VCBOpenCount > (UDF_RESIDUAL_REFERENCE+1))) {
RC = STATUS_NOT_LOCKED;
} else
if((Vcb->VolumeLockFileObject != IrpSp->FileObject)) {
RC = STATUS_INVALID_PARAMETER;
} else {
Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
UDFDoDismountSequence(Vcb, Buf, FALSE);
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
Vcb->WriteSecurity = FALSE;
// disable Eject Request Waiter if any
UDFReleaseResource( &(Vcb->VCBResource) );
VcbAcquired = FALSE;
UDFStopEjectWaiter(Vcb);
RC = STATUS_SUCCESS;
}
try_exit: NOTHING;
} _SEH2_FINALLY {
// Free memory
if(Buf) MyFreePool__(Buf);
// Release all of our resources
if(VcbAcquired)
UDFReleaseResource( &(Vcb->VCBResource) );
} _SEH2_END;
if(!NT_SUCCESS(RC)) {
UDFNotifyVolumeEvent(IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT_FAILED);
}
// Complete the request if there haven't been any exceptions.
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = RC;
return RC;
} // end UDFDismountVolume()
/*
This routine returns the volume allocation bitmap.
Input = the STARTING_LCN_INPUT_BUFFER data structure is passed in
through the input buffer.
Output = the VOLUME_BITMAP_BUFFER data structure is returned through
the output buffer.
We return as much as the user buffer allows starting the specified input
LCN (trucated to a byte). If there is no input buffer, we start at zero.
Arguments:
Irp - Supplies the Irp being processed.
Return Value:
NTSTATUS - The return status for the operation.
*/
NTSTATUS
UDFGetVolumeBitmap(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
// NTSTATUS RC;
PEXTENDED_IO_STACK_LOCATION IrpSp =
(PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
UDFPrint(("UDFGetVolumeBitmap\n"));
ULONG BytesToCopy;
ULONG TotalClusters;
ULONG DesiredClusters;
ULONG StartingCluster;
ULONG InputBufferLength;
ULONG OutputBufferLength;
LARGE_INTEGER StartingLcn;
PVOLUME_BITMAP_BUFFER OutputBuffer;
ULONG i, lim;
PULONG FSBM;
// PULONG Dest;
ULONG LSh;
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
OutputBuffer = (PVOLUME_BITMAP_BUFFER)UDFGetCallersBuffer(IrpContext, Irp);
if(!OutputBuffer)
return STATUS_INVALID_USER_BUFFER;
// Check for a minimum length on the input and output buffers.
if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) ||
(OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) {
UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
return STATUS_BUFFER_TOO_SMALL;
}
// Check if a starting cluster was specified.
TotalClusters = Vcb->FSBM_BitCount;
StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn;
if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) {
UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
} else {
StartingCluster = StartingLcn.LowPart & ~7;
}
OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
DesiredClusters = TotalClusters - StartingCluster;
if (OutputBufferLength < (DesiredClusters + 7) / 8) {
BytesToCopy = OutputBufferLength;
// RC = STATUS_BUFFER_OVERFLOW;
} else {
BytesToCopy = (DesiredClusters + 7) / 8;
// RC = STATUS_SUCCESS;
}
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE );
_SEH2_TRY {
// Fill in the fixed part of the output buffer
OutputBuffer->StartingLcn.QuadPart = StartingCluster;
OutputBuffer->BitmapSize.QuadPart = DesiredClusters;
RtlZeroMemory( &OutputBuffer->Buffer[0], BytesToCopy );
lim = BytesToCopy * 8;
FSBM = (PULONG)(Vcb->FSBM_Bitmap);
LSh = Vcb->LB2B_Bits;
// Dest = (PULONG)(&OutputBuffer->Buffer[0]);
for(i=StartingCluster & ~7; i<lim; i++) {
if(UDFGetFreeBit(FSBM, i<<LSh))
UDFSetFreeBit(FSBM, i);
}
} _SEH2_EXCEPT(UDFExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
BrutePoint();
UDFPrintErr(("UDFGetVolumeBitmap: Exception\n"));
// UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
BrutePoint();
// RC = UDFExceptionHandler(IrpContext, Irp);
UDFReleaseResource(&(Vcb->VCBResource));
UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER;
return STATUS_INVALID_USER_BUFFER;
} _SEH2_END;
UDFReleaseResource(&(Vcb->VCBResource));
UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer);
Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) +
BytesToCopy;
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
} // end UDFGetVolumeBitmap()
NTSTATUS
UDFGetRetrievalPointers(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp,
IN ULONG Special
)
{
NTSTATUS RC;
PEXTENDED_IO_STACK_LOCATION IrpSp =
(PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
PUDF_FILE_INFO FileInfo;
ULONG InputBufferLength;
ULONG OutputBufferLength;
PRETRIEVAL_POINTERS_BUFFER OutputBuffer;
PSTARTING_VCN_INPUT_BUFFER InputBuffer;
LARGE_INTEGER StartingVcn;
int64 AllocationSize;
PEXTENT_MAP SubMapping = NULL;
ULONG SubExtInfoSz;
ULONG i;
ULONG LBS;
ULONG LBSh;
ULONG L2BSh;
UDFPrint(("UDFGetRetrievalPointers\n"));
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
// Get the input and output buffer lengths and pointers.
// Initialize some variables.
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
//OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)UDFGetCallersBuffer( IrpContext, Irp );
if(Special) {
OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->AssociatedIrp.SystemBuffer;
} else {
OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->UserBuffer;
}
InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
if(!InputBuffer) {
InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)OutputBuffer;
}
_SEH2_TRY {
Irp->IoStatus.Information = 0;
// Check for a minimum length on the input and ouput buffers.
if ((InputBufferLength < sizeof(STARTING_VCN_INPUT_BUFFER)) ||
(OutputBufferLength < sizeof(RETRIEVAL_POINTERS_BUFFER))) {
try_return( RC = STATUS_BUFFER_TOO_SMALL );
}
_SEH2_TRY {
if (Irp->RequestorMode != KernelMode) {
ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
InputBufferLength,
sizeof(UCHAR) );
ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(UCHAR) );
}
StartingVcn = InputBuffer->StartingVcn;
} _SEH2_EXCEPT(Irp->RequestorMode != KernelMode ? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH) {
RC = _SEH2_GetExceptionCode();
RC = FsRtlIsNtstatusExpected(RC) ?
RC : STATUS_INVALID_USER_BUFFER;
try_return(RC);
} _SEH2_END;
switch(Special) {
case 0:
FileInfo = Fcb->FileInfo;
break;
case 1:
FileInfo = Vcb->NonAllocFileInfo;
break;
default:
try_return( RC = STATUS_INVALID_PARAMETER );
}
if(!FileInfo) {
try_return( RC = STATUS_OBJECT_NAME_NOT_FOUND );
}
AllocationSize = UDFGetFileAllocationSize(Vcb, FileInfo);
LBS = Vcb->LBlockSize;
LBSh = Vcb->LBlockSizeBits;
L2BSh = Vcb->LB2B_Bits;
if (StartingVcn.HighPart ||
StartingVcn.LowPart >= (ULONG)(AllocationSize >> LBSh)) {
try_return( RC = STATUS_END_OF_FILE );
}
SubExtInfoSz = (OutputBufferLength - FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0])) / (sizeof(LARGE_INTEGER)*2);
// re-use AllocationSize as NextVcn
RC = UDFReadFileLocation__(Vcb, FileInfo, StartingVcn.QuadPart << LBSh,
&SubMapping, &SubExtInfoSz, &AllocationSize);
if(!NT_SUCCESS(RC))
try_return(RC);
OutputBuffer->ExtentCount = SubExtInfoSz;
OutputBuffer->StartingVcn = StartingVcn;
for(i=0; i<SubExtInfoSz; i++) {
// assume, that
// for not-allocated extents we have start Lba = -1
// for not-recorded extents start Lba.LowPart contains real Lba, Lba.HighPart = 0x80000000
// for recorded extents Lba.LowPart contains real Lba, Lba.HighPart = 0
if(SubMapping[i].extLocation == LBA_NOT_ALLOCATED) {
OutputBuffer->Extents[i].Lcn.QuadPart = (int64)(-1);
} else
if(SubMapping[i].extLocation & 0x80000000) {
OutputBuffer->Extents[i].Lcn.LowPart = (SubMapping[i].extLocation & 0x7fffffff) >> L2BSh;
OutputBuffer->Extents[i].Lcn.HighPart = 0x80000000;
} else {
OutputBuffer->Extents[i].Lcn.LowPart = SubMapping[i].extLocation >> L2BSh;
OutputBuffer->Extents[i].Lcn.HighPart = 0;
}
// alignment for last sector
SubMapping[i].extLength += LBS-1;
StartingVcn.QuadPart += SubMapping[i].extLength >> LBSh;
OutputBuffer->Extents[i].NextVcn = StartingVcn;
}
Irp->IoStatus.Information = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]) + i * sizeof(LARGE_INTEGER) * 2;
try_exit: NOTHING;
} _SEH2_FINALLY {
if(SubMapping)
MyFreePool__(SubMapping);
Irp->IoStatus.Status = RC;
} _SEH2_END;
return RC;
} // end UDFGetRetrievalPointers()
NTSTATUS
UDFIsVolumeDirty(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
PULONG VolumeState;
PEXTENDED_IO_STACK_LOCATION IrpSp =
(PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
UDFPrint(("UDFIsVolumeDirty\n"));
Irp->IoStatus.Information = 0;
if (Irp->AssociatedIrp.SystemBuffer != NULL) {
VolumeState = (PULONG)(Irp->AssociatedIrp.SystemBuffer);
} else if (Irp->MdlAddress != NULL) {
VolumeState = (PULONG)MmGetSystemAddressForMdl(Irp->MdlAddress);
} else {
UDFPrintErr((" STATUS_INVALID_USER_BUFFER\n"));
Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER;
return STATUS_INVALID_USER_BUFFER;
}
if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
UDFPrintErr((" STATUS_BUFFER_TOO_SMALL\n"));
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
return STATUS_BUFFER_TOO_SMALL;
}
(*VolumeState) = 0;
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
if(!Ccb) {
UDFPrintErr((" !Ccb\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
if(Vcb != (PVCB)Fcb || !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN)) {
UDFPrintErr((" !Volume\n"));
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
UDFPrintErr((" !Mounted\n"));
Irp->IoStatus.Status = STATUS_VOLUME_DISMOUNTED;
return STATUS_VOLUME_DISMOUNTED;
}
if(Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) {
UDFPrint((" Dirty\n"));
(*VolumeState) |= VOLUME_IS_DIRTY;
Irp->IoStatus.Information = sizeof(ULONG);
} else {
UDFPrint((" Clean\n"));
}
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
} // end UDFIsVolumeDirty()
NTSTATUS
UDFInvalidateVolumes(
IN PtrUDFIrpContext IrpContext,
IN PIRP Irp
)
{
NTSTATUS RC;
PEXTENDED_IO_STACK_LOCATION IrpSp =
(PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
UDFPrint(("UDFInvalidateVolumes\n"));
KIRQL SavedIrql;
LUID TcbPrivilege = {SE_TCB_PRIVILEGE, 0};
HANDLE Handle;
PVPB NewVpb;
PVCB Vcb;
PLIST_ENTRY Link;
PFILE_OBJECT FileToMarkBad;
PDEVICE_OBJECT DeviceToMarkBad;
Irp->IoStatus.Information = 0;
// Check for the correct security access.
// The caller must have the SeTcbPrivilege.
if (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES &&
!SeSinglePrivilegeCheck( TcbPrivilege, UserMode )) {
UDFPrintErr(("UDFInvalidateVolumes: STATUS_PRIVILEGE_NOT_HELD\n"));
Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD;
return STATUS_PRIVILEGE_NOT_HELD;
}
// Try to get a pointer to the device object from the handle passed in.
if (IrpSp->Parameters.FileSystemControl.InputBufferLength != sizeof( HANDLE )) {
UDFPrintErr(("UDFInvalidateVolumes: STATUS_INVALID_PARAMETER\n"));
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
return STATUS_INVALID_PARAMETER;
}
Handle = *((PHANDLE) Irp->AssociatedIrp.SystemBuffer);
RC = ObReferenceObjectByHandle( Handle,
0,
*IoFileObjectType,
KernelMode,
(PVOID*)&FileToMarkBad,
NULL );
if (!NT_SUCCESS(RC)) {
UDFPrintErr(("UDFInvalidateVolumes: can't get handle, RC=%x\n", RC));
Irp->IoStatus.Status = RC;
return RC;
}
// We only needed the pointer, not a reference.
ObDereferenceObject( FileToMarkBad );
// Grab the DeviceObject from the FileObject.
DeviceToMarkBad = FileToMarkBad->DeviceObject;
// Create a new Vpb for this device so that any new opens will mount
// a new volume.
NewVpb = (PVPB)DbgAllocatePoolWithTag( NonPagedPool, sizeof( VPB ), 'bpvU' );
if(!NewVpb) {
UDFPrintErr(("UDFInvalidateVolumes: STATUS_INSUFFICIENT_RESOURCES\n"));
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( NewVpb, sizeof( VPB ) );
NewVpb->Type = IO_TYPE_VPB;
NewVpb->Size = sizeof( VPB );
NewVpb->RealDevice = DeviceToMarkBad;
NewVpb->Flags = DeviceToMarkBad->Vpb->Flags & VPB_REMOVE_PENDING;
// Acquire GlobalDataResource
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
// Nothing can go wrong now.
IoAcquireVpbSpinLock( &SavedIrql );
if (DeviceToMarkBad->Vpb->Flags & VPB_MOUNTED) {
DeviceToMarkBad->Vpb = NewVpb;
NewVpb = NULL;
}
ASSERT( DeviceToMarkBad->Vpb->DeviceObject == NULL );
IoReleaseVpbSpinLock( SavedIrql );
if (NewVpb) {
DbgFreePool( NewVpb );
}
// Walk through all of the Vcb's attached to the global data.
Link = UDFGlobalData.VCBQueue.Flink;
//ASSERT(FALSE);
while (Link != &(UDFGlobalData.VCBQueue)) {
// Get 'next' Vcb
Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
// Move to the next link now since the current Vcb may be deleted.
Link = Link->Flink;
// Acquire Vcb resource
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
if (Vcb->Vpb->RealDevice == DeviceToMarkBad) {
if(!Buf) {
Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)*2);
if(!Buf) {
UDFPrintErr(("UDFInvalidateVolumes: STATUS_INSUFFICIENT_RESOURCES (2)\n"));
UDFReleaseResource(&(Vcb->VCBResource));
MyFreePool__(NewVpb);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
return STATUS_INSUFFICIENT_RESOURCES;
}
}
#ifdef UDF_DELAYED_CLOSE
UDFPrint((" UDFInvalidateVolumes: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
UDFReleaseResource(&(Vcb->VCBResource));
#endif //UDF_DELAYED_CLOSE
if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) {
UDFPrint((" UDFInvalidateVolumes: UDFCloseAllSystemDelayedInDir\n"));
RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
ASSERT(OS_SUCCESS(RC));
}
#ifdef UDF_DELAYED_CLOSE
UDFPrint((" UDFInvalidateVolumes: UDFCloseAllDelayed\n"));
UDFCloseAllDelayed(Vcb);
//ASSERT(OS_SUCCESS(RC));
#endif //UDF_DELAYED_CLOSE
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
UDFDoDismountSequence(Vcb, Buf, FALSE);
UDFReleaseResource(&(Vcb->VCBResource));
UDFStopEjectWaiter(Vcb);
UDFPrint(("UDFInvalidateVolumes: Vcb %x dismounted\n", Vcb));
break;
} else {
UDFPrint(("UDFInvalidateVolumes: skip Vcb %x\n", Vcb));
UDFReleaseResource(&(Vcb->VCBResource));
}
}
// Once we have processed all the mounted logical volumes, we can release
// all acquired global resources and leave (in peace :-)
UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
Irp->IoStatus.Status = STATUS_SUCCESS;
if(Buf) {
UDFPrint(("UDFInvalidateVolumes: free buffer\n"));
MyFreePool__(Buf);
}
// drop volume completly
UDFPrint(("UDFInvalidateVolumes: drop volume completly\n"));
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
UDFScanForDismountedVcb(IrpContext);
UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
UDFPrint(("UDFInvalidateVolumes: done\n"));
return STATUS_SUCCESS;
} // end UDFInvalidateVolumes()