mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 15:18:33 +00:00
2617 lines
88 KiB
C++
2617 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;
|
|
SIZE_T 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_PTR)(PathName.Buffer) - (ULONG_PTR)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()
|