reactos/drivers/filesystems/udfs/devcntrl.cpp

1220 lines
42 KiB
C++
Raw Normal View History

////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////
/*************************************************************************
*
* File: Devcntrl.cpp
*
* Module: UDF File System Driver (Kernel mode execution only)
*
* Description:
* Contains code to handle the "Device IOCTL" dispatch entry point.
*
*************************************************************************/
#include "udffs.h"
#include "CDRW/scsi_port.h"
#define UDF_CURRENT_BUILD 123456789
// define the file specific bug-check id
#ifdef UDF_BUG_CHECK_ID
#undef UDF_BUG_CHECK_ID
#endif
#define UDF_BUG_CHECK_ID UDF_FILE_DEVICE_CONTROL
NTSTATUS
UDFGetFileAllocModeFromICB(
PtrUDFIrpContext PtrIrpContext,
PIRP Irp
);
NTSTATUS
UDFSetFileAllocModeFromICB(
PtrUDFIrpContext IrpContext,
PIRP Irp
);
NTSTATUS
UDFProcessLicenseKey(
PtrUDFIrpContext IrpContext,
PIRP Irp
);
/*#if(_WIN32_WINNT < 0x0400)
#define IOCTL_REDIR_QUERY_PATH CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef struct _QUERY_PATH_REQUEST {
ULONG PathNameLength;
PIO_SECURITY_CONTEXT SecurityContext;
WCHAR FilePathName[1];
} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST;
typedef struct _QUERY_PATH_RESPONSE {
ULONG LengthAccepted;
} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE;
#endif*/
/*************************************************************************
*
* Function: UDFDeviceControl()
*
* Description:
* The I/O Manager will invoke this routine to handle a Device IOCTL
* request
*
* 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
UDFDeviceControl(
PDEVICE_OBJECT DeviceObject, // the logical volume device object
PIRP Irp) // I/O Request Packet
{
NTSTATUS RC = STATUS_SUCCESS;
PtrUDFIrpContext PtrIrpContext = NULL;
BOOLEAN AreWeTopLevel = FALSE;
TmPrint(("UDFDeviceControl: \n"));
FsRtlEnterFileSystem();
ASSERT(DeviceObject);
ASSERT(Irp);
// set the top level context
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
//ASSERT(!UDFIsFSDevObj(DeviceObject));
_SEH2_TRY {
// get an IRP context structure and issue the request
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
if(PtrIrpContext) {
RC = UDFCommonDeviceControl(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())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
} _SEH2_END;
if (AreWeTopLevel) {
IoSetTopLevelIrp(NULL);
}
FsRtlExitFileSystem();
return(RC);
} // end UDFDeviceControl()
/*************************************************************************
*
* Function: UDFCommonDeviceControl()
*
* Description:
* The actual work is performed here. This routine may be invoked in one'
* of the two possible contexts:
* (a) in the context of a system worker thread
* (b) in the context of the original caller
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS/Error
*
*************************************************************************/
NTSTATUS
NTAPI
UDFCommonDeviceControl(
PtrUDFIrpContext PtrIrpContext,
PIRP Irp
)
{
NTSTATUS RC = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = NULL;
// PIO_STACK_LOCATION PtrNextIoStackLocation = NULL;
PFILE_OBJECT FileObject = NULL;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
PVCB Vcb = NULL;
BOOLEAN CompleteIrp = FALSE;
ULONG IoControlCode = 0;
// PVOID BufferPointer = NULL;
BOOLEAN AcquiredVcb = FALSE;
BOOLEAN FSDevObj;
ULONG TrackNumber;
BOOLEAN UnsafeIoctl = TRUE;
UCHAR ScsiCommand;
PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; // FSD buffer
PCDB Cdb;
PCHAR CdbData;
PCHAR ModeSelectData;
UDFPrint(("UDFCommonDeviceControl\n"));
_SEH2_TRY {
// First, get a pointer to the current I/O stack location
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IrpSp);
// Get the IoControlCode value
IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
FileObject = IrpSp->FileObject;
ASSERT(FileObject);
FSDevObj = UDFIsFSDevObj(PtrIrpContext->TargetDeviceObject);
if(FSDevObj) {
switch (IoControlCode) {
case IOCTL_UDF_DISABLE_DRIVER:
case IOCTL_UDF_INVALIDATE_VOLUMES:
case IOCTL_UDF_SET_NOTIFICATION_EVENT:
#ifndef UDF_READ_ONLY_BUILD
case IOCTL_UDF_SEND_LICENSE_KEY:
#endif //UDF_READ_ONLY_BUILD
case IOCTL_UDF_REGISTER_AUTOFORMAT:
break;
default:
UDFPrint(("UDFCommonDeviceControl: STATUS_INVALID_PARAMETER %x for FsDevObj\n", IoControlCode));
CompleteIrp = TRUE;
try_return(RC = STATUS_INVALID_PARAMETER);
}
} else {
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
if(!Ccb) {
UDFPrint((" !Ccb\n"));
goto ioctl_do_default;
}
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
// Check if the IOCTL is suitable for this type of File
if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
// Everything is acceptable for Volume
Vcb = (PVCB)(Fcb);
} else {
Vcb = Fcb->Vcb;
CompleteIrp = TRUE;
// For files/disrs only the following are acceptable
switch (IoControlCode) {
case IOCTL_UDF_GET_RETRIEVAL_POINTERS:
case IOCTL_UDF_GET_FILE_ALLOCATION_MODE:
case IOCTL_UDF_SET_FILE_ALLOCATION_MODE:
break;
default:
UDFPrint(("UDFCommonDeviceControl: STATUS_INVALID_PARAMETER %x for File/Dir Obj\n", IoControlCode));
try_return(RC = STATUS_INVALID_PARAMETER);
}
}
// check 'safe' IOCTLs
switch (IoControlCode) {
case IOCTL_CDROM_RAW_READ:
case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
case IOCTL_DISK_GET_PARTITION_INFO:
case IOCTL_DISK_GET_DRIVE_LAYOUT:
case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
case IOCTL_DISK_GET_PARTITION_INFO_EX:
case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
case IOCTL_STORAGE_CHECK_VERIFY:
case IOCTL_STORAGE_CHECK_VERIFY2:
case IOCTL_DISK_CHECK_VERIFY:
case IOCTL_CDROM_CHECK_VERIFY:
case IOCTL_CDROM_LOAD_MEDIA:
case IOCTL_DISK_LOAD_MEDIA:
case IOCTL_STORAGE_LOAD_MEDIA:
case IOCTL_STORAGE_LOAD_MEDIA2:
case IOCTL_CDROM_GET_CONFIGURATION:
case IOCTL_CDROM_GET_LAST_SESSION:
case IOCTL_CDROM_READ_TOC:
case IOCTL_CDROM_READ_TOC_EX:
case IOCTL_CDROM_PLAY_AUDIO_MSF:
case IOCTL_CDROM_READ_Q_CHANNEL:
case IOCTL_CDROM_PAUSE_AUDIO:
case IOCTL_CDROM_RESUME_AUDIO:
case IOCTL_CDROM_SEEK_AUDIO_MSF:
case IOCTL_CDROM_STOP_AUDIO:
case IOCTL_CDROM_GET_CONTROL:
case IOCTL_CDROM_GET_VOLUME:
case IOCTL_CDROM_SET_VOLUME:
case IOCTL_CDRW_SET_SPEED:
case IOCTL_CDRW_GET_CAPABILITIES:
case IOCTL_CDRW_GET_MEDIA_TYPE_EX:
case IOCTL_CDRW_GET_MEDIA_TYPE:
case IOCTL_DISK_GET_MEDIA_TYPES:
case IOCTL_STORAGE_GET_MEDIA_TYPES:
case IOCTL_STORAGE_GET_MEDIA_TYPES_EX:
case IOCTL_DISK_IS_WRITABLE:
case IOCTL_CDRW_GET_WRITE_MODE:
case IOCTL_CDRW_READ_TRACK_INFO:
case IOCTL_CDRW_READ_DISC_INFO:
case IOCTL_CDRW_BUFFER_CAPACITY:
case IOCTL_CDRW_GET_SIGNATURE:
case IOCTL_CDRW_TEST_UNIT_READY:
case IOCTL_CDRW_GET_LAST_ERROR:
case IOCTL_CDRW_MODE_SENSE:
case IOCTL_CDRW_LL_READ:
case IOCTL_CDRW_READ_ATIP:
case IOCTL_CDRW_READ_CD_TEXT:
case IOCTL_CDRW_READ_TOC_EX:
case IOCTL_CDRW_READ_FULL_TOC:
case IOCTL_CDRW_READ_PMA:
case IOCTL_CDRW_READ_SESSION_INFO:
case IOCTL_CDRW_GET_DEVICE_INFO:
case IOCTL_CDRW_GET_EVENT:
case IOCTL_DVD_READ_STRUCTURE:
case IOCTL_CDRW_GET_DEVICE_NAME:
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
case IOCTL_UDF_GET_RETRIEVAL_POINTERS:
case IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS:
case IOCTL_UDF_GET_FILE_ALLOCATION_MODE:
case IOCTL_UDF_GET_VERSION:
case IOCTL_UDF_IS_VOLUME_JUST_MOUNTED:
case IOCTL_UDF_SET_OPTIONS:
// case :
case FSCTL_IS_VOLUME_DIRTY:
UnsafeIoctl = FALSE;
break;
}
if(IoControlCode != IOCTL_CDROM_DISK_TYPE) {
UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
} else {
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
}
AcquiredVcb = TRUE;
}
UDFPrint(("UDF Irp %x, ctx %x, DevIoCtl %x\n", Irp, PtrIrpContext, IoControlCode));
// We may wish to allow only volume open operations.
switch (IoControlCode) {
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
case IOCTL_SCSI_PASS_THROUGH:
if(!Irp->AssociatedIrp.SystemBuffer)
goto ioctl_do_default;
if(IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) {
Cdb = (PCDB)&(((PSCSI_PASS_THROUGH_DIRECT)(Irp->AssociatedIrp.SystemBuffer))->Cdb);
CdbData = (PCHAR)(((PSCSI_PASS_THROUGH_DIRECT)(Irp->AssociatedIrp.SystemBuffer))->DataBuffer);
} else {
Cdb = (PCDB)&(((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb);
if(((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->DataBufferOffset) {
CdbData = ((PCHAR)Cdb) +
((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->DataBufferOffset;
} else {
CdbData = NULL;
}
}
ScsiCommand = Cdb->CDB6.OperationCode;
if(ScsiCommand == SCSIOP_WRITE_CD) {
UDFPrint(("Write10, LBA %2.2x%2.2x%2.2x%2.2x\n",
Cdb->WRITE_CD.LBA[0],
Cdb->WRITE_CD.LBA[1],
Cdb->WRITE_CD.LBA[2],
Cdb->WRITE_CD.LBA[3]
));
} else
if(ScsiCommand == SCSIOP_WRITE12) {
UDFPrint(("Write12, LBA %2.2x%2.2x%2.2x%2.2x\n",
Cdb->CDB12READWRITE.LBA[0],
Cdb->CDB12READWRITE.LBA[1],
Cdb->CDB12READWRITE.LBA[2],
Cdb->CDB12READWRITE.LBA[3]
));
} else {
}
switch(ScsiCommand) {
case SCSIOP_MODE_SELECT: {
// PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
ModeSelectData = CdbData+4;
switch(ModeSelectData[0]) {
case MODE_PAGE_MRW2:
case MODE_PAGE_WRITE_PARAMS:
case MODE_PAGE_MRW:
UDFPrint(("Unsafe MODE_SELECT_6 via pass-through (%2.2x)\n", ModeSelectData[0]));
goto unsafe_direct_scsi_cmd;
}
break; }
case SCSIOP_MODE_SELECT10: {
// PMODE_PARAMETER_HEADER10 ParamHdr = (PMODE_PARAMETER_HEADER10)CdbData;
ModeSelectData = CdbData+8;
switch(ModeSelectData[0]) {
case MODE_PAGE_MRW2:
case MODE_PAGE_WRITE_PARAMS:
case MODE_PAGE_MRW:
UDFPrint(("Unsafe MODE_SELECT_10 via pass-through (%2.2x)\n", ModeSelectData[0]));
goto unsafe_direct_scsi_cmd;
}
break; }
case SCSIOP_RESERVE_TRACK:
case SCSIOP_SEND_CUE_SHEET:
case SCSIOP_SEND_DVD_STRUCTURE:
case SCSIOP_CLOSE_TRACK_SESSION:
case SCSIOP_FORMAT_UNIT:
case SCSIOP_WRITE6:
case SCSIOP_WRITE_CD:
case SCSIOP_BLANK:
case SCSIOP_WRITE12:
case SCSIOP_SET_STREAMING:
UDFPrint(("UDF Direct media modification via pass-through (%2.2x)\n", ScsiCommand));
unsafe_direct_scsi_cmd:
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED))
goto ioctl_do_default;
UDFPrint(("Forget this volume\n"));
// Acquire Vcb resource (Shared -> Exclusive)
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
UDFReleaseResource(&(Vcb->VCBResource));
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) {
UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
}
#ifdef UDF_DELAYED_CLOSE
// Acquire exclusive access to the Vcb.
UDFCloseAllDelayed(Vcb);
#endif //UDF_DELAYED_CLOSE
// allocate tmp buffer for FSD calls
Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
if(!Buf)
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
AcquiredVcb = TRUE;
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
UDFDoDismountSequence(Vcb, Buf, FALSE);
MyFreePool__(Buf);
Buf = NULL;
Vcb->MediaLockCount = 0;
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
Vcb->WriteSecurity = FALSE;
// Release the Vcb resource.
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
// disable Eject Request Waiter if any
UDFStopEjectWaiter(Vcb);
// Make sure, that volume will never be quick-remounted
// It is very important for ChkUdf utility and
// some CD-recording libraries
Vcb->SerialNumber--;
UDFPrint(("Forgotten\n"));
goto notify_media_change;
case SCSIOP_START_STOP_UNIT:
case SCSIOP_DOORLOCK:
case SCSIOP_DOORUNLOCK:
case SCSIOP_MEDIUM_REMOVAL:
UDFPrint(("UDF Medium/Tray control IOCTL via pass-through\n"));
}
goto ioctl_do_default;
case IOCTL_CDRW_BLANK:
case IOCTL_CDRW_LL_WRITE:
case IOCTL_CDRW_FORMAT_UNIT:
notify_media_change:
/* Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL;
// Make sure, that volume will never be quick-remounted
// It is very important for ChkUdf utility and
// some CD-recording libraries
Vcb->SerialNumber--;
*/ goto ioctl_do_default;
case IOCTL_UDF_REGISTER_AUTOFORMAT: {
UDFPrint(("UDF Register Autoformat\n"));
if(UDFGlobalData.AutoFormatCount) {
RC = STATUS_SHARING_VIOLATION;
} else {
UDFGlobalData.AutoFormatCount = FileObject;
RC = STATUS_SUCCESS;
}
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_UDF_DISABLE_DRIVER: {
UDFPrint(("UDF Disable driver\n"));
IoUnregisterFileSystem(UDFGlobalData.UDFDeviceObject);
// Now, delete any device objects, etc. we may have created
if (UDFGlobalData.UDFDeviceObject) {
IoDeleteDevice(UDFGlobalData.UDFDeviceObject);
UDFGlobalData.UDFDeviceObject = NULL;
}
// free up any memory we might have reserved for zones/lookaside
// lists
if (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_ZONES_INITIALIZED) {
UDFDestroyZones();
}
// delete the resource we may have initialized
if (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_RESOURCE_INITIALIZED) {
// un-initialize this resource
UDFDeleteResource(&(UDFGlobalData.GlobalDataResource));
UDFClearFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED);
}
RC = STATUS_SUCCESS;
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_UDF_INVALIDATE_VOLUMES: {
UDFPrint(("UDF Invaidate volume\n"));
if(AcquiredVcb) {
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
}
RC = UDFInvalidateVolumes( PtrIrpContext, Irp );
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_UDF_SET_NOTIFICATION_EVENT:
{
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(HANDLE))
{
RC = STATUS_INVALID_PARAMETER;
}
else
{
HANDLE MountEventHandle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
if (MountEventHandle)
{
if (!UDFGlobalData.MountEvent)
{
RC = ObReferenceObjectByHandle(
MountEventHandle,
0,
NULL,
UserMode,
(PVOID *) &UDFGlobalData.MountEvent,
NULL);
if (!NT_SUCCESS(RC))
{
UDFGlobalData.MountEvent = NULL;
}
}
else
{
RC = STATUS_INVALID_PARAMETER;
}
}
else
{
if (!UDFGlobalData.MountEvent)
{
RC = STATUS_INVALID_PARAMETER;
}
else
{
ObDereferenceObject(UDFGlobalData.MountEvent);
UDFGlobalData.MountEvent = NULL;
}
}
}
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_UDF_IS_VOLUME_JUST_MOUNTED:
{
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BOOLEAN))
{
RC = STATUS_INVALID_PARAMETER;
}
else
{
*(PBOOLEAN)Irp->AssociatedIrp.SystemBuffer = Vcb->IsVolumeJustMounted;
Vcb->IsVolumeJustMounted = FALSE;
}
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
break;
}
//case FSCTL_GET_RETRIEVAL_POINTERS
case IOCTL_UDF_GET_RETRIEVAL_POINTERS: {
UDFPrint(("UDF: Get Retrieval Pointers\n"));
RC = UDFGetRetrievalPointers( PtrIrpContext, Irp, 0 );
CompleteIrp = TRUE;
break;
}
case IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS: {
UDFPrint(("UDF: Get Spec Retrieval Pointers\n"));
PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN SpecRetrPointer;
SpecRetrPointer = (PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN)(Irp->AssociatedIrp.SystemBuffer);
RC = UDFGetRetrievalPointers( PtrIrpContext, Irp, SpecRetrPointer->Special );
CompleteIrp = TRUE;
break;
}
case IOCTL_UDF_GET_FILE_ALLOCATION_MODE: {
UDFPrint(("UDF: Get File Alloc mode (from ICB)\n"));
RC = UDFGetFileAllocModeFromICB( PtrIrpContext, Irp );
CompleteIrp = TRUE;
break;
}
#ifndef UDF_READ_ONLY_BUILD
case IOCTL_UDF_SET_FILE_ALLOCATION_MODE: {
UDFPrint(("UDF: Set File Alloc mode\n"));
RC = UDFSetFileAllocModeFromICB( PtrIrpContext, Irp );
CompleteIrp = TRUE;
break;
}
#endif //UDF_READ_ONLY_BUILD
case IOCTL_UDF_LOCK_VOLUME_BY_PID:
if(AcquiredVcb) {
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
}
RC = UDFLockVolume( PtrIrpContext, Irp, GetCurrentPID() );
CompleteIrp = TRUE;
break;
case IOCTL_UDF_UNLOCK_VOLUME_BY_PID:
if(AcquiredVcb) {
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
}
RC = UDFUnlockVolume( PtrIrpContext, Irp, GetCurrentPID() );
CompleteIrp = TRUE;
break;
#ifndef UDF_READ_ONLY_BUILD
case IOCTL_UDF_SEND_LICENSE_KEY:
RC = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
CompleteIrp = TRUE;
break;
#endif //UDF_READ_ONLY_BUILD
case IOCTL_UDF_GET_VERSION: {
PUDF_GET_VERSION_OUT udf_ver;
UDFPrint(("UDFUserFsCtrlRequest: IOCTL_UDF_GET_VERSION\n"));
Irp->IoStatus.Information = 0;
CompleteIrp = TRUE;
if(!IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
UDFPrint(("!OutputBufferLength\n"));
try_return(RC = STATUS_SUCCESS);
}
// Check the size of the output buffer.
if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UDF_GET_VERSION_OUT)) {
UDFPrint(("OutputBufferLength < %x\n", sizeof(UDF_GET_VERSION_OUT)));
try_return(RC = STATUS_BUFFER_TOO_SMALL);
}
udf_ver = (PUDF_GET_VERSION_OUT)(Irp->AssociatedIrp.SystemBuffer);
if(!udf_ver) {
UDFPrint(("!udf_ver\n"));
try_return(RC = STATUS_INVALID_USER_BUFFER);
}
RtlZeroMemory(udf_ver, IrpSp->Parameters.DeviceIoControl.OutputBufferLength);
udf_ver->header.Length = sizeof(UDF_GET_VERSION_OUT);
udf_ver->header.DriverVersionMj = 0x00010005;
udf_ver->header.DriverVersionMn = 0x12;
udf_ver->header.DriverVersionBuild = UDF_CURRENT_BUILD;
udf_ver->FSVersionMj = Vcb->CurrentUDFRev >> 8;
udf_ver->FSVersionMn = Vcb->CurrentUDFRev & 0xff;
udf_ver->FSFlags = Vcb->UserFSFlags;
if( ((Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) &&
(Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO))
||
(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ) {
UDFPrint((" UDF_USER_FS_FLAGS_RO\n"));
udf_ver->FSFlags |= UDF_USER_FS_FLAGS_RO;
}
if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) {
UDFPrint((" UDF_USER_FS_FLAGS_OUR_DRIVER\n"));
udf_ver->FSFlags |= UDF_USER_FS_FLAGS_OUR_DRIVER;
}
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
UDFPrint((" UDF_USER_FS_FLAGS_RAW\n"));
udf_ver->FSFlags |= UDF_USER_FS_FLAGS_RAW;
}
if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) {
UDFPrint((" UDF_USER_FS_FLAGS_MEDIA_RO\n"));
udf_ver->FSFlags |= UDF_USER_FS_FLAGS_MEDIA_RO;
}
if(Vcb->FP_disc) {
UDFPrint((" UDF_USER_FS_FLAGS_FP\n"));
udf_ver->FSFlags |= UDF_USER_FS_FLAGS_FP;
}
udf_ver->FSCompatFlags = Vcb->CompatFlags;
udf_ver->FSCfgVersion = Vcb->CfgVersion;
Irp->IoStatus.Information = sizeof(UDF_GET_VERSION_OUT);
RC = STATUS_SUCCESS;
CompleteIrp = TRUE;
break; }
case IOCTL_UDF_SET_OPTIONS: {
PUDF_SET_OPTIONS_IN udf_opt;
BOOLEAN PrevVerifyOnWrite;
UDFPrint(("UDF: IOCTL_UDF_SET_OPTIONS\n"));
Irp->IoStatus.Information = 0;
CompleteIrp = TRUE;
if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UDF_SET_OPTIONS_IN)) {
UDFPrint(("InputBufferLength < %x\n", sizeof(UDF_SET_OPTIONS_IN)));
try_return(RC = STATUS_BUFFER_TOO_SMALL);
}
udf_opt = (PUDF_SET_OPTIONS_IN)(Irp->AssociatedIrp.SystemBuffer);
if(!udf_opt) {
UDFPrint(("!udf_opt\n"));
try_return(RC = STATUS_INVALID_USER_BUFFER);
}
if((udf_opt->header.Flags & UDF_SET_OPTIONS_FLAG_MASK) != UDF_SET_OPTIONS_FLAG_TEMPORARY) {
UDFPrint(("invalid opt target\n"));
try_return(RC = STATUS_INVALID_PARAMETER);
}
if(AcquiredVcb) {
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
}
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
AcquiredVcb = TRUE;
PrevVerifyOnWrite = Vcb->VerifyOnWrite;
Vcb->Cfg = ((PUCHAR)(udf_opt)) + udf_opt->header.HdrLength;
Vcb->CfgLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - offsetof(UDF_SET_OPTIONS_IN, Data);
UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE /*cfg*/);
Vcb->Cfg = NULL;
Vcb->CfgLength = 0;
Vcb->CfgVersion++;
//UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE);
if(PrevVerifyOnWrite != Vcb->VerifyOnWrite) {
if(Vcb->VerifyOnWrite) {
UDFVInit(Vcb);
} else {
WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA);
UDFVFlush(Vcb);
UDFVRelease(Vcb);
}
}
RC = STATUS_SUCCESS;
break; }
#if 0
case IOCTL_UDF_GET_OPTIONS_VERSION: {
PUDF_GET_OPTIONS_VERSION_OUT udf_opt_ver;
UDFPrint(("UDF: IOCTL_UDF_GET_OPTIONS_VERSION\n"));
Irp->IoStatus.Information = 0;
CompleteIrp = TRUE;
if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UDF_GET_OPTIONS_VERSION_OUT)) {
UDFPrint(("OutputBufferLength < %x\n", sizeof(UDF_GET_OPTIONS_VERSION_OUT)));
try_return(RC = STATUS_BUFFER_TOO_SMALL);
}
udf_opt_ver = (PUDF_GET_OPTIONS_VERSION_OUT)(Irp->AssociatedIrp.SystemBuffer);
if(!udf_opt_ver) {
UDFPrint(("!udf_opt-ver\n"));
try_return(RC = STATUS_INVALID_USER_BUFFER);
}
/*
if(AcquiredVcb) {
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
}
UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
AcquiredVcb = TRUE;
*/
udf_opt_ver->CfgVersion = Vcb->CfgVersion;
Irp->IoStatus.Information = sizeof(UDF_GET_OPTIONS_VERSION_OUT);
RC = STATUS_SUCCESS;
break; }
#endif //0
case IOCTL_CDRW_RESET_DRIVER:
UDFPrint(("UDF: IOCTL_CDRW_RESET_DRIVER\n"));
Vcb->MediaLockCount = 0;
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_MEDIA_LOCKED;
goto ioctl_do_default;
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;
CompleteIrp = TRUE;
break;
case FSCTL_IS_VOLUME_DIRTY:
UDFPrint(("UDFUserFsCtrlRequest: FSCTL_IS_VOLUME_DIRTY\n"));
// DASD i/o is always permitted
// So, no-op this call
RC = UDFIsVolumeDirty(PtrIrpContext, Irp);
CompleteIrp = TRUE;
break;
case IOCTL_STORAGE_EJECT_MEDIA:
case IOCTL_DISK_EJECT_MEDIA:
case IOCTL_CDROM_EJECT_MEDIA: {
UDFPrint(("UDF Reset/Eject request\n"));
// PPREVENT_MEDIA_REMOVAL_USER_IN Buf;
if(Vcb->EjectWaiter) {
UDFPrint((" Vcb->EjectWaiter present\n"));
Irp->IoStatus.Information = 0;
Vcb->EjectWaiter->SoftEjectReq = TRUE;
Vcb->SoftEjectReq = TRUE;
CompleteIrp = TRUE;
try_return(RC = STATUS_SUCCESS);
}
UDFPrint((" !Vcb->EjectWaiter\n"));
goto ioctl_do_default;
/*
Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
// Acquire Vcb resource (Shared -> Exclusive)
UDFReleaseResource(&(Vcb->VCBResource));
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
UDFDoDismountSequence(Vcb, Buf, IoControlCode == IOCTL_CDROM_EJECT_MEDIA);
// disable Eject Request Waiter if any
MyFreePool__(Buf);
// Release the Vcb resource.
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
UDFStopEjectWaiter(Vcb);
CompleteIrp = TRUE;
RC = STATUS_SUCCESS;
break;*/
}
case IOCTL_CDROM_DISK_TYPE: {
UDFPrint(("UDF Cdrom Disk Type\n"));
CompleteIrp = TRUE;
// Verify the Vcb in this case to detect if the volume has changed.
Irp->IoStatus.Information = 0;
RC = UDFVerifyVcb(PtrIrpContext,Vcb);
if(!NT_SUCCESS(RC))
try_return(RC);
// Check the size of the output buffer.
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_DISK_DATA_USER_OUT))
try_return(RC = STATUS_BUFFER_TOO_SMALL);
// Copy the data from the Vcb.
((PCDROM_DISK_DATA_USER_OUT)(Irp->AssociatedIrp.SystemBuffer))->DiskData = CDROM_DISK_DATA_TRACK;
for(TrackNumber=Vcb->FirstTrackNum; TrackNumber<Vcb->LastTrackNum; TrackNumber++) {
if((Vcb->TrackMap[TrackNumber].TrackParam & Trk_QSubChan_Type_Mask) ==
Trk_QSubChan_Type_Audio) {
((PCDROM_DISK_DATA_USER_OUT)(Irp->AssociatedIrp.SystemBuffer))->DiskData |= CDROM_DISK_AUDIO_TRACK;
break;
}
}
Irp->IoStatus.Information = sizeof(CDROM_DISK_DATA_USER_OUT);
RC = STATUS_SUCCESS;
break;
}
case IOCTL_CDRW_LOCK_DOOR:
case IOCTL_STORAGE_MEDIA_REMOVAL:
case IOCTL_DISK_MEDIA_REMOVAL:
case IOCTL_CDROM_MEDIA_REMOVAL: {
UDFPrint(("UDF Lock/Unlock\n"));
PPREVENT_MEDIA_REMOVAL_USER_IN buffer; // user supplied buffer
buffer = (PPREVENT_MEDIA_REMOVAL_USER_IN)(Irp->AssociatedIrp.SystemBuffer);
if(!buffer) {
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
UDFPrint(("!mounted\n"));
goto ioctl_do_default;
}
UDFPrint(("abort\n"));
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
UnsafeIoctl = FALSE;
RC = STATUS_INVALID_PARAMETER;
break;
}
if(!buffer->PreventMediaRemoval &&
!Vcb->MediaLockCount) {
UDFPrint(("!locked + unlock req\n"));
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
UDFPrint(("!mounted\n"));
goto ioctl_do_default;
}
#if 0
// allocate tmp buffer for FSD calls
Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
if(!Buf)
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
// Acquire Vcb resource (Shared -> Exclusive)
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
UDFReleaseResource(&(Vcb->VCBResource));
#ifdef UDF_DELAYED_CLOSE
// Acquire exclusive access to the Vcb.
UDFCloseAllDelayed(Vcb);
#endif //UDF_DELAYED_CLOSE
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
UDFDoDismountSequence(Vcb, Buf, FALSE);
MyFreePool__(Buf);
Buf = NULL;
Vcb->MediaLockCount = 0;
// Release the Vcb resource.
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
// disable Eject Request Waiter if any
UDFStopEjectWaiter(Vcb);
#else
// just ignore
#endif
ignore_lock:
UDFPrint(("ignore lock/unlock\n"));
CompleteIrp = TRUE;
Irp->IoStatus.Information = 0;
RC = STATUS_SUCCESS;
break;
}
if(buffer->PreventMediaRemoval) {
UDFPrint(("lock req\n"));
Vcb->MediaLockCount++;
Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_LOCKED;
UnsafeIoctl = FALSE;
} else {
UDFPrint(("unlock req\n"));
if(Vcb->MediaLockCount) {
UDFPrint(("lock count %d\n", Vcb->MediaLockCount));
UnsafeIoctl = FALSE;
Vcb->MediaLockCount--;
}
}
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
UDFPrint(("!mounted\n"));
goto ioctl_do_default;
}
goto ignore_lock;
}
default:
UDFPrint(("default processing Irp %x, ctx %x, DevIoCtl %x\n", Irp, PtrIrpContext, IoControlCode));
ioctl_do_default:
// make sure volume is Sync'ed BEFORE sending unsafe IOCTL
if(Vcb && UnsafeIoctl) {
UDFFlushLogicalVolume(NULL, NULL, Vcb, 0);
UDFPrint((" sync'ed\n"));
}
// Invoke the lower level driver in the chain.
//PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp);
//*PtrNextIoStackLocation = *IrpSp;
IoSkipCurrentIrpStackLocation(Irp);
/*
// Set a completion routine.
IoSetCompletionRoutine(Irp, UDFDevIoctlCompletion, PtrIrpContext, TRUE, TRUE, TRUE);
// Send the request.
*/
RC = IoCallDriver(Vcb->TargetDeviceObject, Irp);
if(!CompleteIrp) {
// since now we do not use IoSetCompletionRoutine()
UDFReleaseIrpContext(PtrIrpContext);
}
break;
}
if(Vcb && UnsafeIoctl) {
UDFPrint((" set UnsafeIoctl\n"));
Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL;
}
try_exit: NOTHING;
} _SEH2_FINALLY {
if(AcquiredVcb) {
UDFReleaseResource(&(Vcb->VCBResource));
AcquiredVcb = FALSE;
}
if(Buf) {
MyFreePool__(Buf);
}
if (!_SEH2_AbnormalTermination() &&
CompleteIrp) {
UDFPrint((" complete Irp %x, ctx %x, status %x, iolen %x\n",
Irp, PtrIrpContext, RC, Irp->IoStatus.Information));
Irp->IoStatus.Status = RC;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
// Release the IRP context
UDFReleaseIrpContext(PtrIrpContext);
}
} _SEH2_END;
return(RC);
} // end UDFCommonDeviceControl()
/*************************************************************************
*
* Function: UDFDevIoctlCompletion()
*
* Description:
* Completion routine.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS
*
*************************************************************************/
NTSTATUS
NTAPI
UDFDevIoctlCompletion(
PDEVICE_OBJECT PtrDeviceObject,
PIRP Irp,
VOID *Context)
{
/* PIO_STACK_LOCATION IrpSp = NULL;
ULONG IoControlCode = 0;*/
PtrUDFIrpContext PtrIrpContext = (PtrUDFIrpContext)Context;
UDFPrint(("UDFDevIoctlCompletion Irp %x, ctx %x\n", Irp, Context));
if (Irp->PendingReturned) {
UDFPrint((" IoMarkIrpPending\n"));
IoMarkIrpPending(Irp);
}
UDFReleaseIrpContext(PtrIrpContext);
/* if(Irp->IoStatus.Status == STATUS_SUCCESS) {
IrpSp = IoGetCurrentIrpStackLocation(Irp);
IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
switch(IoControlCode) {
case IOCTL_CDRW_RESET_DRIVER: {
Vcb->MediaLockCount = 0;
}
}
}*/
return STATUS_SUCCESS;
} // end UDFDevIoctlCompletion()
/*************************************************************************
*
* Function: UDFHandleQueryPath()
*
* Description:
* Handle the MUP request.
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS
*
*************************************************************************/
/*NTSTATUS UDFHandleQueryPath(
VOID *BufferPointer)
{
NTSTATUS RC = STATUS_SUCCESS;
PQUERY_PATH_REQUEST RequestBuffer = (PQUERY_PATH_REQUEST)BufferPointer;
PQUERY_PATH_RESPONSE ReplyBuffer = (PQUERY_PATH_RESPONSE)BufferPointer;
ULONG LengthOfNameToBeMatched = RequestBuffer->PathNameLength;
ULONG LengthOfMatchedName = 0;
WCHAR *NameToBeMatched = RequestBuffer->FilePathName;
UDFPrint(("UDFHandleQueryPath\n"));
// So here we are. Simply check the name supplied.
// We can use whatever algorithm we like to determine whether the
// sent in name is acceptable.
// The first character in the name is always a "\"
// If we like the name sent in (probably, we will like a subset
// of the name), set the matching length value in LengthOfMatchedName.
// if (FoundMatch) {
// ReplyBuffer->LengthAccepted = LengthOfMatchedName;
// } else {
// RC = STATUS_OBJECT_NAME_NOT_FOUND;
// }
return(RC);
}*/
NTSTATUS
UDFGetFileAllocModeFromICB(
PtrUDFIrpContext IrpContext,
PIRP Irp
)
{
PEXTENDED_IO_STACK_LOCATION IrpSp =
(PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
// PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
PUDF_GET_FILE_ALLOCATION_MODE_OUT OutputBuffer;
UDFPrint(("UDFGetFileAllocModeFromICB\n"));
// Decode the file object, the only type of opens we accept are
// user volume opens.
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
Fcb = Ccb->Fcb;
// Vcb = Fcb->Vcb;
Irp->IoStatus.Information = 0;
if(IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(UDF_GET_FILE_ALLOCATION_MODE_OUT))
return STATUS_BUFFER_TOO_SMALL;
OutputBuffer = (PUDF_GET_FILE_ALLOCATION_MODE_OUT)(Irp->AssociatedIrp.SystemBuffer);
if(!OutputBuffer)
return STATUS_INVALID_USER_BUFFER;
OutputBuffer->AllocMode = UDFGetFileICBAllocMode__(Fcb->FileInfo);
Irp->IoStatus.Information = sizeof(UDF_GET_FILE_ALLOCATION_MODE_OUT);
return STATUS_SUCCESS;
} // end UDFGetFileAllocModeFromICB()
#ifndef UDF_READ_ONLY_BUILD
NTSTATUS
UDFSetFileAllocModeFromICB(
PtrUDFIrpContext IrpContext,
PIRP Irp
)
{
PEXTENDED_IO_STACK_LOCATION IrpSp =
(PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PtrUDFFCB Fcb;
PtrUDFCCB Ccb;
PUDF_SET_FILE_ALLOCATION_MODE_IN InputBuffer;
NTSTATUS RC;
UCHAR AllocMode;
UDFPrint(("UDFSetFileAllocModeFromICB\n"));
Ccb = (PtrUDFCCB)(IrpSp->FileObject->FsContext2);
Fcb = Ccb->Fcb;
Vcb = Fcb->Vcb;
Irp->IoStatus.Information = 0;
if(IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(UDF_SET_FILE_ALLOCATION_MODE_IN))
return STATUS_BUFFER_TOO_SMALL;
InputBuffer = (PUDF_SET_FILE_ALLOCATION_MODE_IN)(Irp->AssociatedIrp.SystemBuffer);
if(!InputBuffer)
return STATUS_INVALID_USER_BUFFER;
UDFFlushAFile(Fcb, Ccb, &(Irp->IoStatus), 0);
RC = Irp->IoStatus.Status;
if(!NT_SUCCESS(RC))
return RC;
if(InputBuffer->AllocMode != ICB_FLAG_AD_IN_ICB) {
AllocMode = UDFGetFileICBAllocMode__(Fcb->FileInfo);
if(AllocMode == ICB_FLAG_AD_IN_ICB) {
RC = UDFConvertFEToNonInICB(Vcb, Fcb->FileInfo, InputBuffer->AllocMode);
} else
if(AllocMode != InputBuffer->AllocMode) {
RC = STATUS_INVALID_PARAMETER;
} else {
RC = STATUS_SUCCESS;
}
} else {
RC = STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
} // end UDFSetFileAllocModeFromICB()
#endif //UDF_READ_ONLY_BUILD