1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "Device IOCTL" dispatch entry point.
15 *************************************************************************/
19 #include "CDRW/scsi_port.h"
21 #define UDF_CURRENT_BUILD 123456789
23 // define the file specific bug-check id
24 #ifdef UDF_BUG_CHECK_ID
25 #undef UDF_BUG_CHECK_ID
27 #define UDF_BUG_CHECK_ID UDF_FILE_DEVICE_CONTROL
30 UDFGetFileAllocModeFromICB(
31 PtrUDFIrpContext PtrIrpContext
,
36 UDFSetFileAllocModeFromICB(
37 PtrUDFIrpContext IrpContext
,
43 PtrUDFIrpContext IrpContext
,
47 /*#if(_WIN32_WINNT < 0x0400)
48 #define IOCTL_REDIR_QUERY_PATH CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS)
50 typedef struct _QUERY_PATH_REQUEST {
52 PIO_SECURITY_CONTEXT SecurityContext;
53 WCHAR FilePathName[1];
54 } QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST;
56 typedef struct _QUERY_PATH_RESPONSE {
58 } QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE;
63 /*************************************************************************
65 * Function: UDFDeviceControl()
68 * The I/O Manager will invoke this routine to handle a Device IOCTL
71 * Expected Interrupt Level (for execution) :
73 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
74 * to be deferred to a worker thread context)
76 * Return Value: STATUS_SUCCESS/Error
78 *************************************************************************/
82 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
83 PIRP Irp
) // I/O Request Packet
85 NTSTATUS RC
= STATUS_SUCCESS
;
86 PtrUDFIrpContext PtrIrpContext
= NULL
;
87 BOOLEAN AreWeTopLevel
= FALSE
;
89 TmPrint(("UDFDeviceControl: \n"));
91 FsRtlEnterFileSystem();
95 // set the top level context
96 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
97 //ASSERT(!UDFIsFSDevObj(DeviceObject));
101 // get an IRP context structure and issue the request
102 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
104 RC
= UDFCommonDeviceControl(PtrIrpContext
, Irp
);
106 RC
= STATUS_INSUFFICIENT_RESOURCES
;
107 Irp
->IoStatus
.Status
= RC
;
108 Irp
->IoStatus
.Information
= 0;
110 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
113 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
115 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
117 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
121 IoSetTopLevelIrp(NULL
);
124 FsRtlExitFileSystem();
127 } // end UDFDeviceControl()
130 /*************************************************************************
132 * Function: UDFCommonDeviceControl()
135 * The actual work is performed here. This routine may be invoked in one'
136 * of the two possible contexts:
137 * (a) in the context of a system worker thread
138 * (b) in the context of the original caller
140 * Expected Interrupt Level (for execution) :
144 * Return Value: STATUS_SUCCESS/Error
146 *************************************************************************/
149 UDFCommonDeviceControl(
150 PtrUDFIrpContext PtrIrpContext
,
154 NTSTATUS RC
= STATUS_SUCCESS
;
155 PIO_STACK_LOCATION IrpSp
= NULL
;
156 // PIO_STACK_LOCATION PtrNextIoStackLocation = NULL;
157 PFILE_OBJECT FileObject
= NULL
;
158 PtrUDFFCB Fcb
= NULL
;
159 PtrUDFCCB Ccb
= NULL
;
161 BOOLEAN CompleteIrp
= FALSE
;
162 ULONG IoControlCode
= 0;
163 // PVOID BufferPointer = NULL;
164 BOOLEAN AcquiredVcb
= FALSE
;
167 BOOLEAN UnsafeIoctl
= TRUE
;
169 PPREVENT_MEDIA_REMOVAL_USER_IN Buf
= NULL
; // FSD buffer
172 PCHAR ModeSelectData
;
174 UDFPrint(("UDFCommonDeviceControl\n"));
177 // First, get a pointer to the current I/O stack location
178 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
181 // Get the IoControlCode value
182 IoControlCode
= IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
;
184 FileObject
= IrpSp
->FileObject
;
187 FSDevObj
= UDFIsFSDevObj(PtrIrpContext
->TargetDeviceObject
);
190 switch (IoControlCode
) {
191 case IOCTL_UDF_DISABLE_DRIVER
:
192 case IOCTL_UDF_INVALIDATE_VOLUMES
:
193 case IOCTL_UDF_SET_NOTIFICATION_EVENT
:
194 #ifndef UDF_READ_ONLY_BUILD
195 case IOCTL_UDF_SEND_LICENSE_KEY
:
196 #endif //UDF_READ_ONLY_BUILD
197 case IOCTL_UDF_REGISTER_AUTOFORMAT
:
200 UDFPrint(("UDFCommonDeviceControl: STATUS_INVALID_PARAMETER %x for FsDevObj\n", IoControlCode
));
202 try_return(RC
= STATUS_INVALID_PARAMETER
);
205 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
207 UDFPrint((" !Ccb\n"));
208 goto ioctl_do_default
;
214 // Check if the IOCTL is suitable for this type of File
215 if (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) {
216 // Everything is acceptable for Volume
221 // For files/disrs only the following are acceptable
222 switch (IoControlCode
) {
223 case IOCTL_UDF_GET_RETRIEVAL_POINTERS
:
224 case IOCTL_UDF_GET_FILE_ALLOCATION_MODE
:
225 case IOCTL_UDF_SET_FILE_ALLOCATION_MODE
:
228 UDFPrint(("UDFCommonDeviceControl: STATUS_INVALID_PARAMETER %x for File/Dir Obj\n", IoControlCode
));
229 try_return(RC
= STATUS_INVALID_PARAMETER
);
232 // check 'safe' IOCTLs
233 switch (IoControlCode
) {
234 case IOCTL_CDROM_RAW_READ
:
236 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
237 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
238 case IOCTL_DISK_GET_PARTITION_INFO
:
239 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
241 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
:
242 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
243 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
244 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
246 case IOCTL_STORAGE_CHECK_VERIFY
:
247 case IOCTL_STORAGE_CHECK_VERIFY2
:
248 case IOCTL_DISK_CHECK_VERIFY
:
249 case IOCTL_CDROM_CHECK_VERIFY
:
251 case IOCTL_CDROM_LOAD_MEDIA
:
252 case IOCTL_DISK_LOAD_MEDIA
:
253 case IOCTL_STORAGE_LOAD_MEDIA
:
254 case IOCTL_STORAGE_LOAD_MEDIA2
:
256 case IOCTL_CDROM_GET_CONFIGURATION
:
257 case IOCTL_CDROM_GET_LAST_SESSION
:
258 case IOCTL_CDROM_READ_TOC
:
259 case IOCTL_CDROM_READ_TOC_EX
:
260 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
261 case IOCTL_CDROM_READ_Q_CHANNEL
:
262 case IOCTL_CDROM_PAUSE_AUDIO
:
263 case IOCTL_CDROM_RESUME_AUDIO
:
264 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
265 case IOCTL_CDROM_STOP_AUDIO
:
266 case IOCTL_CDROM_GET_CONTROL
:
267 case IOCTL_CDROM_GET_VOLUME
:
268 case IOCTL_CDROM_SET_VOLUME
:
270 case IOCTL_CDRW_SET_SPEED
:
271 case IOCTL_CDRW_GET_CAPABILITIES
:
272 case IOCTL_CDRW_GET_MEDIA_TYPE_EX
:
273 case IOCTL_CDRW_GET_MEDIA_TYPE
:
275 case IOCTL_DISK_GET_MEDIA_TYPES
:
276 case IOCTL_STORAGE_GET_MEDIA_TYPES
:
277 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX
:
279 case IOCTL_DISK_IS_WRITABLE
:
281 case IOCTL_CDRW_GET_WRITE_MODE
:
282 case IOCTL_CDRW_READ_TRACK_INFO
:
283 case IOCTL_CDRW_READ_DISC_INFO
:
284 case IOCTL_CDRW_BUFFER_CAPACITY
:
285 case IOCTL_CDRW_GET_SIGNATURE
:
286 case IOCTL_CDRW_TEST_UNIT_READY
:
287 case IOCTL_CDRW_GET_LAST_ERROR
:
288 case IOCTL_CDRW_MODE_SENSE
:
289 case IOCTL_CDRW_LL_READ
:
290 case IOCTL_CDRW_READ_ATIP
:
291 case IOCTL_CDRW_READ_CD_TEXT
:
292 case IOCTL_CDRW_READ_TOC_EX
:
293 case IOCTL_CDRW_READ_FULL_TOC
:
294 case IOCTL_CDRW_READ_PMA
:
295 case IOCTL_CDRW_READ_SESSION_INFO
:
296 case IOCTL_CDRW_GET_DEVICE_INFO
:
297 case IOCTL_CDRW_GET_EVENT
:
299 case IOCTL_DVD_READ_STRUCTURE
:
301 case IOCTL_CDRW_GET_DEVICE_NAME
:
302 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
304 case IOCTL_UDF_GET_RETRIEVAL_POINTERS
:
305 case IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS
:
306 case IOCTL_UDF_GET_FILE_ALLOCATION_MODE
:
307 case IOCTL_UDF_GET_VERSION
:
308 case IOCTL_UDF_IS_VOLUME_JUST_MOUNTED
:
309 case IOCTL_UDF_SET_OPTIONS
:
312 case FSCTL_IS_VOLUME_DIRTY
:
318 if(IoControlCode
!= IOCTL_CDROM_DISK_TYPE
) {
319 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
321 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
326 UDFPrint(("UDF Irp %x, ctx %x, DevIoCtl %x\n", Irp
, PtrIrpContext
, IoControlCode
));
328 // We may wish to allow only volume open operations.
329 switch (IoControlCode
) {
331 case IOCTL_SCSI_PASS_THROUGH_DIRECT
:
332 case IOCTL_SCSI_PASS_THROUGH
:
334 if(!Irp
->AssociatedIrp
.SystemBuffer
)
335 goto ioctl_do_default
;
337 if(IoControlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
) {
338 Cdb
= (PCDB
)&(((PSCSI_PASS_THROUGH_DIRECT
)(Irp
->AssociatedIrp
.SystemBuffer
))->Cdb
);
339 CdbData
= (PCHAR
)(((PSCSI_PASS_THROUGH_DIRECT
)(Irp
->AssociatedIrp
.SystemBuffer
))->DataBuffer
);
341 Cdb
= (PCDB
)&(((PSCSI_PASS_THROUGH
)(Irp
->AssociatedIrp
.SystemBuffer
))->Cdb
);
342 if(((PSCSI_PASS_THROUGH
)(Irp
->AssociatedIrp
.SystemBuffer
))->DataBufferOffset
) {
343 CdbData
= ((PCHAR
)Cdb
) +
344 ((PSCSI_PASS_THROUGH
)(Irp
->AssociatedIrp
.SystemBuffer
))->DataBufferOffset
;
349 ScsiCommand
= Cdb
->CDB6
.OperationCode
;
351 if(ScsiCommand
== SCSIOP_WRITE_CD
) {
352 UDFPrint(("Write10, LBA %2.2x%2.2x%2.2x%2.2x\n",
353 Cdb
->WRITE_CD
.LBA
[0],
354 Cdb
->WRITE_CD
.LBA
[1],
355 Cdb
->WRITE_CD
.LBA
[2],
359 if(ScsiCommand
== SCSIOP_WRITE12
) {
360 UDFPrint(("Write12, LBA %2.2x%2.2x%2.2x%2.2x\n",
361 Cdb
->CDB12READWRITE
.LBA
[0],
362 Cdb
->CDB12READWRITE
.LBA
[1],
363 Cdb
->CDB12READWRITE
.LBA
[2],
364 Cdb
->CDB12READWRITE
.LBA
[3]
369 switch(ScsiCommand
) {
370 case SCSIOP_MODE_SELECT
: {
371 // PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
372 ModeSelectData
= CdbData
+4;
373 switch(ModeSelectData
[0]) {
375 case MODE_PAGE_WRITE_PARAMS
:
377 UDFPrint(("Unsafe MODE_SELECT_6 via pass-through (%2.2x)\n", ModeSelectData
[0]));
378 goto unsafe_direct_scsi_cmd
;
382 case SCSIOP_MODE_SELECT10
: {
383 // PMODE_PARAMETER_HEADER10 ParamHdr = (PMODE_PARAMETER_HEADER10)CdbData;
384 ModeSelectData
= CdbData
+8;
385 switch(ModeSelectData
[0]) {
387 case MODE_PAGE_WRITE_PARAMS
:
389 UDFPrint(("Unsafe MODE_SELECT_10 via pass-through (%2.2x)\n", ModeSelectData
[0]));
390 goto unsafe_direct_scsi_cmd
;
394 case SCSIOP_RESERVE_TRACK
:
395 case SCSIOP_SEND_CUE_SHEET
:
396 case SCSIOP_SEND_DVD_STRUCTURE
:
397 case SCSIOP_CLOSE_TRACK_SESSION
:
398 case SCSIOP_FORMAT_UNIT
:
400 case SCSIOP_WRITE_CD
:
403 case SCSIOP_SET_STREAMING
:
404 UDFPrint(("UDF Direct media modification via pass-through (%2.2x)\n", ScsiCommand
));
405 unsafe_direct_scsi_cmd
:
406 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
))
407 goto ioctl_do_default
;
409 UDFPrint(("Forget this volume\n"));
410 // Acquire Vcb resource (Shared -> Exclusive)
411 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
412 UDFReleaseResource(&(Vcb
->VCBResource
));
414 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
)) {
415 UDFCloseAllSystemDelayedInDir(Vcb
, Vcb
->RootDirFCB
->FileInfo
);
417 #ifdef UDF_DELAYED_CLOSE
418 // Acquire exclusive access to the Vcb.
419 UDFCloseAllDelayed(Vcb
);
420 #endif //UDF_DELAYED_CLOSE
422 // allocate tmp buffer for FSD calls
423 Buf
= (PPREVENT_MEDIA_REMOVAL_USER_IN
)MyAllocatePool__(NonPagedPool
, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN
));
425 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
427 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
429 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
431 UDFDoDismountSequence(Vcb
, Buf
, FALSE
);
434 Vcb
->MediaLockCount
= 0;
436 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_MOUNTED
;
437 Vcb
->WriteSecurity
= FALSE
;
439 // Release the Vcb resource.
440 UDFReleaseResource(&(Vcb
->VCBResource
));
442 // disable Eject Request Waiter if any
443 UDFStopEjectWaiter(Vcb
);
445 // Make sure, that volume will never be quick-remounted
446 // It is very important for ChkUdf utility and
447 // some CD-recording libraries
450 UDFPrint(("Forgotten\n"));
452 goto notify_media_change
;
454 case SCSIOP_START_STOP_UNIT
:
455 case SCSIOP_DOORLOCK
:
456 case SCSIOP_DOORUNLOCK
:
457 case SCSIOP_MEDIUM_REMOVAL
:
458 UDFPrint(("UDF Medium/Tray control IOCTL via pass-through\n"));
460 goto ioctl_do_default
;
462 case IOCTL_CDRW_BLANK
:
463 case IOCTL_CDRW_LL_WRITE
:
464 case IOCTL_CDRW_FORMAT_UNIT
:
467 /* Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL;
468 // Make sure, that volume will never be quick-remounted
469 // It is very important for ChkUdf utility and
470 // some CD-recording libraries
472 */ goto ioctl_do_default
;
474 case IOCTL_UDF_REGISTER_AUTOFORMAT
: {
476 UDFPrint(("UDF Register Autoformat\n"));
477 if(UDFGlobalData
.AutoFormatCount
) {
478 RC
= STATUS_SHARING_VIOLATION
;
480 UDFGlobalData
.AutoFormatCount
= FileObject
;
484 Irp
->IoStatus
.Information
= 0;
488 case IOCTL_UDF_DISABLE_DRIVER
: {
490 UDFPrint(("UDF Disable driver\n"));
491 IoUnregisterFileSystem(UDFGlobalData
.UDFDeviceObject
);
492 // Now, delete any device objects, etc. we may have created
493 if (UDFGlobalData
.UDFDeviceObject
) {
494 IoDeleteDevice(UDFGlobalData
.UDFDeviceObject
);
495 UDFGlobalData
.UDFDeviceObject
= NULL
;
498 // free up any memory we might have reserved for zones/lookaside
500 if (UDFGlobalData
.UDFFlags
& UDF_DATA_FLAGS_ZONES_INITIALIZED
) {
504 // delete the resource we may have initialized
505 if (UDFGlobalData
.UDFFlags
& UDF_DATA_FLAGS_RESOURCE_INITIALIZED
) {
506 // un-initialize this resource
507 UDFDeleteResource(&(UDFGlobalData
.GlobalDataResource
));
508 UDFClearFlag(UDFGlobalData
.UDFFlags
, UDF_DATA_FLAGS_RESOURCE_INITIALIZED
);
512 Irp
->IoStatus
.Information
= 0;
515 case IOCTL_UDF_INVALIDATE_VOLUMES
: {
516 UDFPrint(("UDF Invaidate volume\n"));
518 UDFReleaseResource(&(Vcb
->VCBResource
));
521 RC
= UDFInvalidateVolumes( PtrIrpContext
, Irp
);
523 Irp
->IoStatus
.Information
= 0;
527 case IOCTL_UDF_SET_NOTIFICATION_EVENT
:
529 if (IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(HANDLE
))
531 RC
= STATUS_INVALID_PARAMETER
;
535 HANDLE MountEventHandle
= *(PHANDLE
)Irp
->AssociatedIrp
.SystemBuffer
;
536 if (MountEventHandle
)
538 if (!UDFGlobalData
.MountEvent
)
540 RC
= ObReferenceObjectByHandle(
545 (PVOID
*) &UDFGlobalData
.MountEvent
,
550 UDFGlobalData
.MountEvent
= NULL
;
555 RC
= STATUS_INVALID_PARAMETER
;
560 if (!UDFGlobalData
.MountEvent
)
562 RC
= STATUS_INVALID_PARAMETER
;
566 ObDereferenceObject(UDFGlobalData
.MountEvent
);
567 UDFGlobalData
.MountEvent
= NULL
;
573 Irp
->IoStatus
.Information
= 0;
577 case IOCTL_UDF_IS_VOLUME_JUST_MOUNTED
:
579 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(BOOLEAN
))
581 RC
= STATUS_INVALID_PARAMETER
;
585 *(PBOOLEAN
)Irp
->AssociatedIrp
.SystemBuffer
= Vcb
->IsVolumeJustMounted
;
586 Vcb
->IsVolumeJustMounted
= FALSE
;
590 Irp
->IoStatus
.Information
= 0;
595 //case FSCTL_GET_RETRIEVAL_POINTERS
596 case IOCTL_UDF_GET_RETRIEVAL_POINTERS
: {
597 UDFPrint(("UDF: Get Retrieval Pointers\n"));
598 RC
= UDFGetRetrievalPointers( PtrIrpContext
, Irp
, 0 );
602 case IOCTL_UDF_GET_SPEC_RETRIEVAL_POINTERS
: {
603 UDFPrint(("UDF: Get Spec Retrieval Pointers\n"));
604 PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN SpecRetrPointer
;
605 SpecRetrPointer
= (PUDF_GET_SPEC_RETRIEVAL_POINTERS_IN
)(Irp
->AssociatedIrp
.SystemBuffer
);
606 RC
= UDFGetRetrievalPointers( PtrIrpContext
, Irp
, SpecRetrPointer
->Special
);
610 case IOCTL_UDF_GET_FILE_ALLOCATION_MODE
: {
611 UDFPrint(("UDF: Get File Alloc mode (from ICB)\n"));
612 RC
= UDFGetFileAllocModeFromICB( PtrIrpContext
, Irp
);
616 #ifndef UDF_READ_ONLY_BUILD
617 case IOCTL_UDF_SET_FILE_ALLOCATION_MODE
: {
618 UDFPrint(("UDF: Set File Alloc mode\n"));
619 RC
= UDFSetFileAllocModeFromICB( PtrIrpContext
, Irp
);
623 #endif //UDF_READ_ONLY_BUILD
624 case IOCTL_UDF_LOCK_VOLUME_BY_PID
:
626 UDFReleaseResource(&(Vcb
->VCBResource
));
629 RC
= UDFLockVolume( PtrIrpContext
, Irp
, GetCurrentPID() );
632 case IOCTL_UDF_UNLOCK_VOLUME_BY_PID
:
634 UDFReleaseResource(&(Vcb
->VCBResource
));
637 RC
= UDFUnlockVolume( PtrIrpContext
, Irp
, GetCurrentPID() );
640 #ifndef UDF_READ_ONLY_BUILD
641 case IOCTL_UDF_SEND_LICENSE_KEY
:
644 Irp
->IoStatus
.Information
= 0;
645 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
648 #endif //UDF_READ_ONLY_BUILD
649 case IOCTL_UDF_GET_VERSION
: {
651 PUDF_GET_VERSION_OUT udf_ver
;
653 UDFPrint(("UDFUserFsCtrlRequest: IOCTL_UDF_GET_VERSION\n"));
655 Irp
->IoStatus
.Information
= 0;
658 if(!IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
) {
659 UDFPrint(("!OutputBufferLength\n"));
660 try_return(RC
= STATUS_SUCCESS
);
662 // Check the size of the output buffer.
663 if(IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(UDF_GET_VERSION_OUT
)) {
664 UDFPrint(("OutputBufferLength < %x\n", sizeof(UDF_GET_VERSION_OUT
)));
665 try_return(RC
= STATUS_BUFFER_TOO_SMALL
);
668 udf_ver
= (PUDF_GET_VERSION_OUT
)(Irp
->AssociatedIrp
.SystemBuffer
);
670 UDFPrint(("!udf_ver\n"));
671 try_return(RC
= STATUS_INVALID_USER_BUFFER
);
674 RtlZeroMemory(udf_ver
, IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
);
676 udf_ver
->header
.Length
= sizeof(UDF_GET_VERSION_OUT
);
677 udf_ver
->header
.DriverVersionMj
= 0x00010005;
678 udf_ver
->header
.DriverVersionMn
= 0x12;
679 udf_ver
->header
.DriverVersionBuild
= UDF_CURRENT_BUILD
;
681 udf_ver
->FSVersionMj
= Vcb
->CurrentUDFRev
>> 8;
682 udf_ver
->FSVersionMn
= Vcb
->CurrentUDFRev
& 0xff;
683 udf_ver
->FSFlags
= Vcb
->UserFSFlags
;
684 if( ((Vcb
->origIntegrityType
== INTEGRITY_TYPE_OPEN
) &&
685 (Vcb
->CompatFlags
& UDF_VCB_IC_DIRTY_RO
))
687 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) ) {
688 UDFPrint((" UDF_USER_FS_FLAGS_RO\n"));
689 udf_ver
->FSFlags
|= UDF_USER_FS_FLAGS_RO
;
691 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_OUR_DEVICE_DRIVER
) {
692 UDFPrint((" UDF_USER_FS_FLAGS_OUR_DRIVER\n"));
693 udf_ver
->FSFlags
|= UDF_USER_FS_FLAGS_OUR_DRIVER
;
695 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) {
696 UDFPrint((" UDF_USER_FS_FLAGS_RAW\n"));
697 udf_ver
->FSFlags
|= UDF_USER_FS_FLAGS_RAW
;
699 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_MEDIA_READ_ONLY
) {
700 UDFPrint((" UDF_USER_FS_FLAGS_MEDIA_RO\n"));
701 udf_ver
->FSFlags
|= UDF_USER_FS_FLAGS_MEDIA_RO
;
704 UDFPrint((" UDF_USER_FS_FLAGS_FP\n"));
705 udf_ver
->FSFlags
|= UDF_USER_FS_FLAGS_FP
;
707 udf_ver
->FSCompatFlags
= Vcb
->CompatFlags
;
709 udf_ver
->FSCfgVersion
= Vcb
->CfgVersion
;
711 Irp
->IoStatus
.Information
= sizeof(UDF_GET_VERSION_OUT
);
716 case IOCTL_UDF_SET_OPTIONS
: {
718 PUDF_SET_OPTIONS_IN udf_opt
;
719 BOOLEAN PrevVerifyOnWrite
;
721 UDFPrint(("UDF: IOCTL_UDF_SET_OPTIONS\n"));
723 Irp
->IoStatus
.Information
= 0;
726 if(IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(UDF_SET_OPTIONS_IN
)) {
727 UDFPrint(("InputBufferLength < %x\n", sizeof(UDF_SET_OPTIONS_IN
)));
728 try_return(RC
= STATUS_BUFFER_TOO_SMALL
);
731 udf_opt
= (PUDF_SET_OPTIONS_IN
)(Irp
->AssociatedIrp
.SystemBuffer
);
733 UDFPrint(("!udf_opt\n"));
734 try_return(RC
= STATUS_INVALID_USER_BUFFER
);
737 if((udf_opt
->header
.Flags
& UDF_SET_OPTIONS_FLAG_MASK
) != UDF_SET_OPTIONS_FLAG_TEMPORARY
) {
738 UDFPrint(("invalid opt target\n"));
739 try_return(RC
= STATUS_INVALID_PARAMETER
);
743 UDFReleaseResource(&(Vcb
->VCBResource
));
746 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
749 PrevVerifyOnWrite
= Vcb
->VerifyOnWrite
;
751 Vcb
->Cfg
= ((PUCHAR
)(udf_opt
)) + udf_opt
->header
.HdrLength
;
752 Vcb
->CfgLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
- offsetof(UDF_SET_OPTIONS_IN
, Data
);
753 UDFReadRegKeys(Vcb
, TRUE
/*update*/, TRUE
/*cfg*/);
757 //UDFReadRegKeys(Vcb, TRUE /*update*/, TRUE);
758 if(PrevVerifyOnWrite
!= Vcb
->VerifyOnWrite
) {
759 if(Vcb
->VerifyOnWrite
) {
762 WCacheFlushBlocks__(&(Vcb
->FastCache
), Vcb
, 0, Vcb
->LastLBA
);
771 case IOCTL_UDF_GET_OPTIONS_VERSION
: {
773 PUDF_GET_OPTIONS_VERSION_OUT udf_opt_ver
;
775 UDFPrint(("UDF: IOCTL_UDF_GET_OPTIONS_VERSION\n"));
777 Irp
->IoStatus
.Information
= 0;
780 if(IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(UDF_GET_OPTIONS_VERSION_OUT
)) {
781 UDFPrint(("OutputBufferLength < %x\n", sizeof(UDF_GET_OPTIONS_VERSION_OUT
)));
782 try_return(RC
= STATUS_BUFFER_TOO_SMALL
);
785 udf_opt_ver
= (PUDF_GET_OPTIONS_VERSION_OUT
)(Irp
->AssociatedIrp
.SystemBuffer
);
787 UDFPrint(("!udf_opt-ver\n"));
788 try_return(RC
= STATUS_INVALID_USER_BUFFER
);
792 UDFReleaseResource(&(Vcb->VCBResource));
795 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
798 udf_opt_ver
->CfgVersion
= Vcb
->CfgVersion
;
799 Irp
->IoStatus
.Information
= sizeof(UDF_GET_OPTIONS_VERSION_OUT
);
804 case IOCTL_CDRW_RESET_DRIVER
:
806 UDFPrint(("UDF: IOCTL_CDRW_RESET_DRIVER\n"));
807 Vcb
->MediaLockCount
= 0;
808 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_MEDIA_LOCKED
;
809 goto ioctl_do_default
;
811 case FSCTL_ALLOW_EXTENDED_DASD_IO
:
813 UDFPrint(("UDFUserFsCtrlRequest: FSCTL_ALLOW_EXTENDED_DASD_IO\n"));
814 // DASD i/o is always permitted
815 // So, no-op this call
818 Irp
->IoStatus
.Information
= 0;
819 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
823 case FSCTL_IS_VOLUME_DIRTY
:
825 UDFPrint(("UDFUserFsCtrlRequest: FSCTL_IS_VOLUME_DIRTY\n"));
826 // DASD i/o is always permitted
827 // So, no-op this call
828 RC
= UDFIsVolumeDirty(PtrIrpContext
, Irp
);
832 case IOCTL_STORAGE_EJECT_MEDIA
:
833 case IOCTL_DISK_EJECT_MEDIA
:
834 case IOCTL_CDROM_EJECT_MEDIA
: {
836 UDFPrint(("UDF Reset/Eject request\n"));
837 // PPREVENT_MEDIA_REMOVAL_USER_IN Buf;
839 if(Vcb
->EjectWaiter
) {
840 UDFPrint((" Vcb->EjectWaiter present\n"));
841 Irp
->IoStatus
.Information
= 0;
842 Vcb
->EjectWaiter
->SoftEjectReq
= TRUE
;
843 Vcb
->SoftEjectReq
= TRUE
;
845 try_return(RC
= STATUS_SUCCESS
);
847 UDFPrint((" !Vcb->EjectWaiter\n"));
848 goto ioctl_do_default
;
850 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
851 if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
852 // Acquire Vcb resource (Shared -> Exclusive)
853 UDFReleaseResource(&(Vcb->VCBResource));
854 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
856 Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
857 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
859 UDFDoDismountSequence(Vcb, Buf, IoControlCode == IOCTL_CDROM_EJECT_MEDIA);
860 // disable Eject Request Waiter if any
862 // Release the Vcb resource.
863 UDFReleaseResource(&(Vcb->VCBResource));
865 UDFStopEjectWaiter(Vcb);
870 case IOCTL_CDROM_DISK_TYPE
: {
872 UDFPrint(("UDF Cdrom Disk Type\n"));
874 // Verify the Vcb in this case to detect if the volume has changed.
875 Irp
->IoStatus
.Information
= 0;
876 RC
= UDFVerifyVcb(PtrIrpContext
,Vcb
);
880 // Check the size of the output buffer.
881 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(CDROM_DISK_DATA_USER_OUT
))
882 try_return(RC
= STATUS_BUFFER_TOO_SMALL
);
884 // Copy the data from the Vcb.
885 ((PCDROM_DISK_DATA_USER_OUT
)(Irp
->AssociatedIrp
.SystemBuffer
))->DiskData
= CDROM_DISK_DATA_TRACK
;
886 for(TrackNumber
=Vcb
->FirstTrackNum
; TrackNumber
<Vcb
->LastTrackNum
; TrackNumber
++) {
887 if((Vcb
->TrackMap
[TrackNumber
].TrackParam
& Trk_QSubChan_Type_Mask
) ==
888 Trk_QSubChan_Type_Audio
) {
889 ((PCDROM_DISK_DATA_USER_OUT
)(Irp
->AssociatedIrp
.SystemBuffer
))->DiskData
|= CDROM_DISK_AUDIO_TRACK
;
894 Irp
->IoStatus
.Information
= sizeof(CDROM_DISK_DATA_USER_OUT
);
899 case IOCTL_CDRW_LOCK_DOOR
:
900 case IOCTL_STORAGE_MEDIA_REMOVAL
:
901 case IOCTL_DISK_MEDIA_REMOVAL
:
902 case IOCTL_CDROM_MEDIA_REMOVAL
: {
903 UDFPrint(("UDF Lock/Unlock\n"));
904 PPREVENT_MEDIA_REMOVAL_USER_IN buffer
; // user supplied buffer
905 buffer
= (PPREVENT_MEDIA_REMOVAL_USER_IN
)(Irp
->AssociatedIrp
.SystemBuffer
);
907 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) {
908 UDFPrint(("!mounted\n"));
909 goto ioctl_do_default
;
911 UDFPrint(("abort\n"));
913 Irp
->IoStatus
.Information
= 0;
915 RC
= STATUS_INVALID_PARAMETER
;
918 if(!buffer
->PreventMediaRemoval
&&
919 !Vcb
->MediaLockCount
) {
921 UDFPrint(("!locked + unlock req\n"));
922 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) {
923 UDFPrint(("!mounted\n"));
924 goto ioctl_do_default
;
927 // allocate tmp buffer for FSD calls
928 Buf
= (PPREVENT_MEDIA_REMOVAL_USER_IN
)MyAllocatePool__(NonPagedPool
, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN
));
930 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
932 // Acquire Vcb resource (Shared -> Exclusive)
933 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
934 UDFReleaseResource(&(Vcb
->VCBResource
));
936 #ifdef UDF_DELAYED_CLOSE
937 // Acquire exclusive access to the Vcb.
938 UDFCloseAllDelayed(Vcb
);
939 #endif //UDF_DELAYED_CLOSE
941 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
942 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
944 UDFDoDismountSequence(Vcb
, Buf
, FALSE
);
947 Vcb
->MediaLockCount
= 0;
948 // Release the Vcb resource.
949 UDFReleaseResource(&(Vcb
->VCBResource
));
951 // disable Eject Request Waiter if any
952 UDFStopEjectWaiter(Vcb
);
957 UDFPrint(("ignore lock/unlock\n"));
959 Irp
->IoStatus
.Information
= 0;
963 if(buffer
->PreventMediaRemoval
) {
964 UDFPrint(("lock req\n"));
965 Vcb
->MediaLockCount
++;
966 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_MEDIA_LOCKED
;
969 UDFPrint(("unlock req\n"));
970 if(Vcb
->MediaLockCount
) {
971 UDFPrint(("lock count %d\n", Vcb
->MediaLockCount
));
973 Vcb
->MediaLockCount
--;
976 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) {
977 UDFPrint(("!mounted\n"));
978 goto ioctl_do_default
;
984 UDFPrint(("default processing Irp %x, ctx %x, DevIoCtl %x\n", Irp
, PtrIrpContext
, IoControlCode
));
987 // make sure volume is Sync'ed BEFORE sending unsafe IOCTL
988 if(Vcb
&& UnsafeIoctl
) {
989 UDFFlushLogicalVolume(NULL
, NULL
, Vcb
, 0);
990 UDFPrint((" sync'ed\n"));
992 // Invoke the lower level driver in the chain.
993 //PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp);
994 //*PtrNextIoStackLocation = *IrpSp;
995 IoSkipCurrentIrpStackLocation(Irp
);
997 // Set a completion routine.
998 IoSetCompletionRoutine(Irp, UDFDevIoctlCompletion, PtrIrpContext, TRUE, TRUE, TRUE);
1001 RC
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
1003 // since now we do not use IoSetCompletionRoutine()
1004 UDFReleaseIrpContext(PtrIrpContext
);
1009 if(Vcb
&& UnsafeIoctl
) {
1010 UDFPrint((" set UnsafeIoctl\n"));
1011 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_UNSAFE_IOCTL
;
1019 UDFReleaseResource(&(Vcb
->VCBResource
));
1020 AcquiredVcb
= FALSE
;
1027 if (!_SEH2_AbnormalTermination() &&
1029 UDFPrint((" complete Irp %x, ctx %x, status %x, iolen %x\n",
1030 Irp
, PtrIrpContext
, RC
, Irp
->IoStatus
.Information
));
1031 Irp
->IoStatus
.Status
= RC
;
1033 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1034 // Release the IRP context
1035 UDFReleaseIrpContext(PtrIrpContext
);
1040 } // end UDFCommonDeviceControl()
1043 /*************************************************************************
1045 * Function: UDFDevIoctlCompletion()
1048 * Completion routine.
1050 * Expected Interrupt Level (for execution) :
1052 * IRQL_PASSIVE_LEVEL
1054 * Return Value: STATUS_SUCCESS
1056 *************************************************************************/
1059 UDFDevIoctlCompletion(
1060 PDEVICE_OBJECT PtrDeviceObject
,
1064 /* PIO_STACK_LOCATION IrpSp = NULL;
1065 ULONG IoControlCode = 0;*/
1066 PtrUDFIrpContext PtrIrpContext
= (PtrUDFIrpContext
)Context
;
1068 UDFPrint(("UDFDevIoctlCompletion Irp %x, ctx %x\n", Irp
, Context
));
1069 if (Irp
->PendingReturned
) {
1070 UDFPrint((" IoMarkIrpPending\n"));
1071 IoMarkIrpPending(Irp
);
1074 UDFReleaseIrpContext(PtrIrpContext
);
1075 /* if(Irp->IoStatus.Status == STATUS_SUCCESS) {
1076 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1077 IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
1079 switch(IoControlCode) {
1080 case IOCTL_CDRW_RESET_DRIVER: {
1081 Vcb->MediaLockCount = 0;
1086 return STATUS_SUCCESS
;
1087 } // end UDFDevIoctlCompletion()
1090 /*************************************************************************
1092 * Function: UDFHandleQueryPath()
1095 * Handle the MUP request.
1097 * Expected Interrupt Level (for execution) :
1099 * IRQL_PASSIVE_LEVEL
1101 * Return Value: STATUS_SUCCESS
1103 *************************************************************************/
1104 /*NTSTATUS UDFHandleQueryPath(
1105 VOID *BufferPointer)
1107 NTSTATUS RC = STATUS_SUCCESS;
1108 PQUERY_PATH_REQUEST RequestBuffer = (PQUERY_PATH_REQUEST)BufferPointer;
1109 PQUERY_PATH_RESPONSE ReplyBuffer = (PQUERY_PATH_RESPONSE)BufferPointer;
1110 ULONG LengthOfNameToBeMatched = RequestBuffer->PathNameLength;
1111 ULONG LengthOfMatchedName = 0;
1112 WCHAR *NameToBeMatched = RequestBuffer->FilePathName;
1114 UDFPrint(("UDFHandleQueryPath\n"));
1115 // So here we are. Simply check the name supplied.
1116 // We can use whatever algorithm we like to determine whether the
1117 // sent in name is acceptable.
1118 // The first character in the name is always a "\"
1119 // If we like the name sent in (probably, we will like a subset
1120 // of the name), set the matching length value in LengthOfMatchedName.
1122 // if (FoundMatch) {
1123 // ReplyBuffer->LengthAccepted = LengthOfMatchedName;
1125 // RC = STATUS_OBJECT_NAME_NOT_FOUND;
1132 UDFGetFileAllocModeFromICB(
1133 PtrUDFIrpContext IrpContext
,
1137 PEXTENDED_IO_STACK_LOCATION IrpSp
=
1138 (PEXTENDED_IO_STACK_LOCATION
)IoGetCurrentIrpStackLocation( Irp
);
1143 PUDF_GET_FILE_ALLOCATION_MODE_OUT OutputBuffer
;
1145 UDFPrint(("UDFGetFileAllocModeFromICB\n"));
1147 // Decode the file object, the only type of opens we accept are
1148 // user volume opens.
1149 Ccb
= (PtrUDFCCB
)(IrpSp
->FileObject
->FsContext2
);
1153 Irp
->IoStatus
.Information
= 0;
1154 if(IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(UDF_GET_FILE_ALLOCATION_MODE_OUT
))
1155 return STATUS_BUFFER_TOO_SMALL
;
1157 OutputBuffer
= (PUDF_GET_FILE_ALLOCATION_MODE_OUT
)(Irp
->AssociatedIrp
.SystemBuffer
);
1159 return STATUS_INVALID_USER_BUFFER
;
1161 OutputBuffer
->AllocMode
= UDFGetFileICBAllocMode__(Fcb
->FileInfo
);
1162 Irp
->IoStatus
.Information
= sizeof(UDF_GET_FILE_ALLOCATION_MODE_OUT
);
1164 return STATUS_SUCCESS
;
1165 } // end UDFGetFileAllocModeFromICB()
1167 #ifndef UDF_READ_ONLY_BUILD
1169 UDFSetFileAllocModeFromICB(
1170 PtrUDFIrpContext IrpContext
,
1174 PEXTENDED_IO_STACK_LOCATION IrpSp
=
1175 (PEXTENDED_IO_STACK_LOCATION
)IoGetCurrentIrpStackLocation( Irp
);
1180 PUDF_SET_FILE_ALLOCATION_MODE_IN InputBuffer
;
1184 UDFPrint(("UDFSetFileAllocModeFromICB\n"));
1186 Ccb
= (PtrUDFCCB
)(IrpSp
->FileObject
->FsContext2
);
1190 Irp
->IoStatus
.Information
= 0;
1191 if(IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
< sizeof(UDF_SET_FILE_ALLOCATION_MODE_IN
))
1192 return STATUS_BUFFER_TOO_SMALL
;
1194 InputBuffer
= (PUDF_SET_FILE_ALLOCATION_MODE_IN
)(Irp
->AssociatedIrp
.SystemBuffer
);
1196 return STATUS_INVALID_USER_BUFFER
;
1198 UDFFlushAFile(Fcb
, Ccb
, &(Irp
->IoStatus
), 0);
1199 RC
= Irp
->IoStatus
.Status
;
1203 if(InputBuffer
->AllocMode
!= ICB_FLAG_AD_IN_ICB
) {
1204 AllocMode
= UDFGetFileICBAllocMode__(Fcb
->FileInfo
);
1205 if(AllocMode
== ICB_FLAG_AD_IN_ICB
) {
1206 RC
= UDFConvertFEToNonInICB(Vcb
, Fcb
->FileInfo
, InputBuffer
->AllocMode
);
1208 if(AllocMode
!= InputBuffer
->AllocMode
) {
1209 RC
= STATUS_INVALID_PARAMETER
;
1211 RC
= STATUS_SUCCESS
;
1214 RC
= STATUS_INVALID_PARAMETER
;
1217 return STATUS_SUCCESS
;
1218 } // end UDFSetFileAllocModeFromICB()
1219 #endif //UDF_READ_ONLY_BUILD