4 Copyright (c) 1989-2000 Microsoft Corporation
12 This module declares the global data used by the Cdfs file system.
14 This module also handles the dispath routines in the Fsd threads as well as
15 handling the IrpContext and Irp through the exception path.
23 BOOLEAN CdTestTopLevel
= TRUE
;
24 BOOLEAN CdTestRaisedStatus
= TRUE
;
25 BOOLEAN CdBreakOnAnyRaise
= FALSE
;
26 BOOLEAN CdTraceRaises
= FALSE
;
27 NTSTATUS CdInterestingExceptionCodes
[] = { STATUS_DISK_CORRUPT_ERROR
,
28 STATUS_FILE_CORRUPT_ERROR
,
29 0, 0, 0, 0, 0, 0, 0, 0 };
33 // The Bug check file id for this module
36 #define BugCheckFileId (CDFS_BUG_CHECK_CDDATA)
39 // Global data structures
43 FAST_IO_DISPATCH CdFastIoDispatch
;
46 // Reserved directory strings.
49 WCHAR CdUnicodeSelfArray
[] = { L
'.' };
50 WCHAR CdUnicodeParentArray
[] = { L
'.', L
'.' };
52 UNICODE_STRING CdUnicodeDirectoryNames
[] = {
53 { 2, 2, CdUnicodeSelfArray
},
54 { 4, 4, CdUnicodeParentArray
}
58 // Volume descriptor identifier strings.
61 CHAR CdHsgId
[] = { 'C', 'D', 'R', 'O', 'M' };
62 CHAR CdIsoId
[] = { 'C', 'D', '0', '0', '1' };
63 CHAR CdXaId
[] = { 'C', 'D', '-', 'X', 'A', '0', '0', '1' };
66 // Volume label for audio disks.
69 WCHAR CdAudioLabel
[] = { L
'A', L
'u', L
'd', L
'i', L
'o', L
' ', L
'C', L
'D' };
70 USHORT CdAudioLabelLength
= sizeof( CdAudioLabel
);
73 // Pseudo file names for audio disks.
76 CHAR CdAudioFileName
[] = { 'T', 'r', 'a', 'c', 'k', '0', '0', '.', 'c', 'd', 'a' };
77 UCHAR CdAudioFileNameLength
= sizeof( CdAudioFileName
);
78 ULONG CdAudioDirentSize
= FIELD_OFFSET( RAW_DIRENT
, FileId
) + sizeof( CdAudioFileName
) + sizeof( SYSTEM_USE_XA
);
79 ULONG CdAudioDirentsPerSector
= SECTOR_SIZE
/ (FIELD_OFFSET( RAW_DIRENT
, FileId
) + sizeof( CdAudioFileName
) + sizeof( SYSTEM_USE_XA
));
80 ULONG CdAudioSystemUseOffset
= FIELD_OFFSET( RAW_DIRENT
, FileId
) + sizeof( CdAudioFileName
);
83 // Escape sequences for mounting Unicode volumes.
86 PCHAR CdJolietEscape
[] = { "%/@", "%/C", "%/E" };
89 // Audio Play Files consist completely of this header block. These
90 // files are readable in the root of any audio disc regardless of
91 // the capabilities of the drive.
93 // The "Unique Disk ID Number" is a calculated value consisting of
94 // a combination of parameters, including the number of tracks and
95 // the starting locations of those tracks.
97 // Applications interpreting CDDA RIFF files should be advised that
98 // additional RIFF file chunks may be added to this header in the
99 // future in order to add information, such as the disk and song title.
102 LONG CdAudioPlayHeader
[] = {
103 0x46464952, // Chunk ID = 'RIFF'
104 4 * 11 - 8, // Chunk Size = (file size - 8)
105 0x41444443, // 'CDDA'
106 0x20746d66, // 'fmt '
107 24, // Chunk Size (of 'fmt ' subchunk) = 24
108 0x00000001, // WORD Format Tag, WORD Track Number
109 0x00000000, // DWORD Unique Disk ID Number
110 0x00000000, // DWORD Track Starting Sector (LBN)
111 0x00000000, // DWORD Track Length (LBN count)
112 0x00000000, // DWORD Track Starting Sector (MSF)
113 0x00000000 // DWORD Track Length (MSF)
116 // Audio Philes begin with this header block to identify the data as a
117 // PCM waveform. AudioPhileHeader is coded as if it has no data included
118 // in the waveform. Data must be added in 2352-byte multiples.
120 // Fields marked 'ADJUST' need to be adjusted based on the size of the
121 // data: Add (nSectors*2352) to the DWORDs at offsets 1*4 and 10*4.
123 // File Size of TRACK??.WAV = nSectors*2352 + sizeof(AudioPhileHeader)
124 // RIFF('WAVE' fmt(1, 2, 44100, 176400, 16, 4) data( <CD Audio Raw Data> )
126 // The number of sectors in a CD-XA CD-DA file is (DataLen/2048).
127 // CDFS will expose these files to applications as if they were just
128 // 'WAVE' files, adjusting the file size so that the RIFF file is valid.
130 // NT NOTE: We do not do any fidelity adjustment. These are presented as raw
131 // 2352 byte sectors - 95 has the glimmer of an idea to allow CDFS to expose
132 // the CDXA CDDA data at different sampling rates in a virtual directory
133 // structure, but we will never do that.
136 LONG CdXAAudioPhileHeader
[] = {
137 0x46464952, // Chunk ID = 'RIFF'
138 -8, // Chunk Size = (file size - 8) ADJUST1
139 0x45564157, // 'WAVE'
140 0x20746d66, // 'fmt '
141 16, // Chunk Size (of 'fmt ' subchunk) = 16
142 0x00020001, // WORD Format Tag WORD nChannels
143 44100, // DWORD nSamplesPerSecond
144 2352 * 75, // DWORD nAvgBytesPerSec
145 0x00100004, // WORD nBlockAlign WORD nBitsPerSample
146 0x61746164, // 'data'
147 -44 // <CD Audio Raw Data> ADJUST2
151 // XA Files begin with this RIFF header block to identify the data as
152 // raw CD-XA sectors. Data must be added in 2352-byte multiples.
154 // This header is added to all CD-XA files which are marked as having
155 // mode2form2 sectors.
157 // Fields marked 'ADJUST' need to be adjusted based on the size of the
158 // data: Add file size to the marked DWORDS.
160 // File Size of TRACK??.WAV = nSectors*2352 + sizeof(XAFileHeader)
162 // RIFF('CDXA' FMT(Owner, Attr, 'X', 'A', FileNum, 0) data ( <CDXA Raw Data> )
165 LONG CdXAFileHeader
[] = {
166 0x46464952, // Chunk ID = 'RIFF'
167 -8, // Chunk Size = (file size - 8) ADJUST
168 0x41584443, // 'CDXA'
169 0x20746d66, // 'fmt '
170 16, // Chunk Size (of CDXA chunk) = 16
172 0x41580000, // WORD Attributes
173 // BYTE Signature byte 1 'X'
174 // BYTE Signature byte 2 'A'
175 0, // BYTE File Number
176 0, // BYTE Reserved[7]
177 0x61746164, // 'data'
178 -44 // <CD-XA Raw Sectors> ADJUST
181 #ifdef CDFS_TELEMETRY_DATA
184 // Telemetry Data for reporting
187 CDFS_TELEMETRY_DATA_CONTEXT CdTelemetryData
;
189 #endif // CDFS_TELEMETRY_DATA
192 #pragma alloc_text(PAGE, CdFastIoCheckIfPossible)
193 #pragma alloc_text(PAGE, CdSerial32)
194 #pragma alloc_text(PAGE, CdSetThreadContext)
197 _IRQL_requires_max_(APC_LEVEL
)
198 __drv_dispatchType(DRIVER_DISPATCH
)
199 __drv_dispatchType(IRP_MJ_CREATE
)
200 __drv_dispatchType(IRP_MJ_CLOSE
)
201 __drv_dispatchType(IRP_MJ_READ
)
202 __drv_dispatchType(IRP_MJ_WRITE
)
203 __drv_dispatchType(IRP_MJ_QUERY_INFORMATION
)
204 __drv_dispatchType(IRP_MJ_SET_INFORMATION
)
205 __drv_dispatchType(IRP_MJ_QUERY_VOLUME_INFORMATION
)
206 __drv_dispatchType(IRP_MJ_DIRECTORY_CONTROL
)
207 __drv_dispatchType(IRP_MJ_FILE_SYSTEM_CONTROL
)
208 __drv_dispatchType(IRP_MJ_DEVICE_CONTROL
)
209 __drv_dispatchType(IRP_MJ_LOCK_CONTROL
)
210 __drv_dispatchType(IRP_MJ_CLEANUP
)
211 __drv_dispatchType(IRP_MJ_PNP
)
212 __drv_dispatchType(IRP_MJ_SHUTDOWN
)
215 _In_ PDEVICE_OBJECT DeviceObject
,
223 This is the driver entry to all of the Fsd dispatch points.
225 Conceptually the Io routine will call this routine on all requests
226 to the file system. We case on the type of request and invoke the
227 correct handler for this type of request. There is an exception filter
228 to catch any exceptions in the CDFS code as well as the CDFS process
231 This routine allocates and initializes the IrpContext for this request as
232 well as updating the top-level thread context as necessary. We may loop
233 in this routine if we need to retry the request for any reason. The
234 status code STATUS_CANT_WAIT is used to indicate this. Suppose the disk
235 in the drive has changed. An Fsd request will proceed normally until it
236 recognizes this condition. STATUS_VERIFY_REQUIRED is raised at that point
237 and the exception code will handle the verify and either return
238 STATUS_CANT_WAIT or STATUS_PENDING depending on whether the request was
243 DeviceObject - Supplies the volume device object for this request
245 Irp - Supplies the Irp being processed
249 NTSTATUS - The FSD status for the IRP
254 THREAD_CONTEXT ThreadContext
= {0};
255 PIRP_CONTEXT IrpContext
= NULL
;
259 PVOID PreviousTopLevel
;
266 KIRQL SaveIrql
= KeGetCurrentIrql();
270 ASSERT_OPTIONAL_IRP( Irp
);
272 UNREFERENCED_PARAMETER( DeviceObject
);
274 FsRtlEnterFileSystem();
277 PreviousTopLevel
= IoGetTopLevelIrp();
281 // Loop until this request has been completed or posted.
287 // Use a try-except to handle the exception cases.
293 // If the IrpContext is NULL then this is the first pass through
297 if (IrpContext
== NULL
) {
300 // Decide if this request is waitable an allocate the IrpContext.
301 // If the file object in the stack location is NULL then this
302 // is a mount which is always waitable. Otherwise we look at
303 // the file object flags.
306 if (IoGetCurrentIrpStackLocation( Irp
)->FileObject
== NULL
) {
312 Wait
= CanFsdWait( Irp
);
315 IrpContext
= CdCreateIrpContext( Irp
, Wait
);
318 // Update the thread context information.
321 CdSetThreadContext( IrpContext
, &ThreadContext
);
324 NT_ASSERT( !CdTestTopLevel
||
325 SafeNodeType( IrpContext
->TopLevel
) == CDFS_NTC_IRP_CONTEXT
);
329 // Otherwise cleanup the IrpContext for the retry.
335 // Set the MORE_PROCESSING flag to make sure the IrpContext
336 // isn't inadvertently deleted here. Then cleanup the
337 // IrpContext to perform the retry.
340 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_MORE_PROCESSING
);
341 CdCleanupIrpContext( IrpContext
, FALSE
);
345 // Case on the major irp code.
348 switch (IrpContext
->MajorFunction
) {
352 Status
= CdCommonCreate( IrpContext
, Irp
);
357 Status
= CdCommonClose( IrpContext
, Irp
);
363 // If this is an Mdl complete request, don't go through
367 if (FlagOn( IrpContext
->MinorFunction
, IRP_MN_COMPLETE
)) {
369 Status
= CdCompleteMdl( IrpContext
, Irp
);
373 Status
= CdCommonRead( IrpContext
, Irp
);
380 Status
= CdCommonWrite( IrpContext
, Irp
);
383 case IRP_MJ_QUERY_INFORMATION
:
385 Status
= CdCommonQueryInfo( IrpContext
, Irp
);
388 case IRP_MJ_SET_INFORMATION
:
390 Status
= CdCommonSetInfo( IrpContext
, Irp
);
393 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
395 Status
= CdCommonQueryVolInfo( IrpContext
, Irp
);
398 case IRP_MJ_DIRECTORY_CONTROL
:
400 Status
= CdCommonDirControl( IrpContext
, Irp
);
403 case IRP_MJ_FILE_SYSTEM_CONTROL
:
405 Status
= CdCommonFsControl( IrpContext
, Irp
);
408 case IRP_MJ_DEVICE_CONTROL
:
410 Status
= CdCommonDevControl( IrpContext
, Irp
);
413 case IRP_MJ_LOCK_CONTROL
:
415 Status
= CdCommonLockControl( IrpContext
, Irp
);
418 case IRP_MJ_CLEANUP
:
420 Status
= CdCommonCleanup( IrpContext
, Irp
);
425 Status
= CdCommonPnp( IrpContext
, Irp
);
428 case IRP_MJ_SHUTDOWN
:
430 Status
= CdCommonShutdown( IrpContext
, Irp
);
435 Status
= STATUS_INVALID_DEVICE_REQUEST
;
436 CdCompleteRequest( IrpContext
, Irp
, Status
);
439 } _SEH2_EXCEPT( CdExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
441 Status
= CdProcessException( IrpContext
, Irp
, _SEH2_GetExceptionCode() );
444 } while (Status
== STATUS_CANT_WAIT
);
447 NT_ASSERT( !CdTestTopLevel
||
448 (PreviousTopLevel
== IoGetTopLevelIrp()) );
451 FsRtlExitFileSystem();
453 NT_ASSERT( SaveIrql
== KeGetCurrentIrql( ));
463 _In_ PIRP_CONTEXT IrpContext
,
464 _In_ NTSTATUS Status
,
465 _In_ BOOLEAN NormalizeStatus
,
466 _In_opt_ ULONG FileId
,
470 BOOLEAN BreakIn
= FALSE
;
472 AssertVerifyDevice( IrpContext
, Status
);
476 DbgPrint( "%p CdRaiseStatusEx 0x%x @ fid %d, line %d\n", PsGetCurrentThread(), Status
, FileId
, Line
);
479 if (CdTestRaisedStatus
&& !CdBreakOnAnyRaise
) {
484 Index
< (sizeof( CdInterestingExceptionCodes
) / sizeof( CdInterestingExceptionCodes
[0]));
487 if ((STATUS_SUCCESS
!= CdInterestingExceptionCodes
[Index
]) &&
488 (CdInterestingExceptionCodes
[Index
] == Status
)) {
496 if (BreakIn
|| CdBreakOnAnyRaise
) {
498 DbgPrint( "CDFS: Breaking on raised status %08x (BI=%d,BA=%d)\n", Status
, BreakIn
, CdBreakOnAnyRaise
);
499 DbgPrint( "CDFS: (FILEID %d LINE %d)\n", FileId
, Line
);
500 DbgPrint( "CDFS: Contact CDFS.SYS component owner for triage.\n");
501 DbgPrint( "CDFS: 'eb %p 0;eb %p 0' to disable this alert.\n", &CdTestRaisedStatus
, &CdBreakOnAnyRaise
);
506 if (NormalizeStatus
) {
508 IrpContext
->ExceptionStatus
= FsRtlNormalizeNtstatus( Status
, STATUS_UNEXPECTED_IO_ERROR
);
512 IrpContext
->ExceptionStatus
= Status
;
515 IrpContext
->RaisedAtLineFile
= (FileId
<< 16) | Line
;
517 ExRaiseStatus( IrpContext
->ExceptionStatus
);
525 _Inout_ PIRP_CONTEXT IrpContext
,
526 _In_ PEXCEPTION_POINTERS ExceptionPointer
533 This routine is used to decide whether we will handle a raised exception
534 status. If CDFS explicitly raised an error then this status is already
535 in the IrpContext. We choose which is the correct status code and
536 either indicate that we will handle the exception or bug-check the system.
540 ExceptionCode - Supplies the exception code to being checked.
544 ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
549 NTSTATUS ExceptionCode
;
550 BOOLEAN TestStatus
= TRUE
;
552 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext
);
554 ExceptionCode
= ExceptionPointer
->ExceptionRecord
->ExceptionCode
;
557 // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
558 // from the exception record.
561 if ((ExceptionCode
== STATUS_IN_PAGE_ERROR
) &&
562 (ExceptionPointer
->ExceptionRecord
->NumberParameters
>= 3)) {
565 (NTSTATUS
)ExceptionPointer
->ExceptionRecord
->ExceptionInformation
[2];
569 // If there is an Irp context then check which status code to use.
572 if (ARGUMENT_PRESENT( IrpContext
)) {
574 if (IrpContext
->ExceptionStatus
== STATUS_SUCCESS
) {
577 // Store the real status into the IrpContext.
580 IrpContext
->ExceptionStatus
= ExceptionCode
;
585 // No need to test the status code if we raised it ourselves.
592 AssertVerifyDevice( IrpContext
, IrpContext
->ExceptionStatus
);
595 // Bug check if this status is not supported.
598 if (TestStatus
&& !FsRtlIsNtstatusExpected( ExceptionCode
)) {
601 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "We're corrupted." )
603 CdBugCheck( (ULONG_PTR
) ExceptionPointer
->ExceptionRecord
,
604 (ULONG_PTR
) ExceptionPointer
->ContextRecord
,
605 (ULONG_PTR
) ExceptionPointer
->ExceptionRecord
->ExceptionAddress
);
609 return EXCEPTION_EXECUTE_HANDLER
;
614 _Requires_lock_held_(_Global_critical_region_
)
617 _In_opt_ PIRP_CONTEXT IrpContext
,
619 _In_ NTSTATUS ExceptionCode
626 This routine processes an exception. It either completes the request
627 with the exception status in the IrpContext, sends this off to the Fsp
628 workque or causes it to be retried in the current thread if a verification
631 If the volume needs to be verified (STATUS_VERIFY_REQUIRED) and we can
632 do the work in the current thread we will translate the status code
633 to STATUS_CANT_WAIT to indicate that we need to retry the request.
637 Irp - Supplies the Irp being processed
639 ExceptionCode - Supplies the normalized exception status being handled
643 NTSTATUS - Returns the results of either posting the Irp or the
644 saved completion status.
649 PDEVICE_OBJECT Device
= NULL
;
653 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext
);
657 // If there is not an irp context, then complete the request with the
658 // current status code.
661 if (!ARGUMENT_PRESENT( IrpContext
)) {
663 CdCompleteRequest( NULL
, Irp
, ExceptionCode
);
664 return ExceptionCode
;
668 // Get the real exception status from the IrpContext.
671 ExceptionCode
= IrpContext
->ExceptionStatus
;
674 // Check if we are posting this request. One of the following must be true
675 // if we are to post a request.
677 // - Status code is STATUS_CANT_WAIT and the request is asynchronous
678 // or we are forcing this to be posted.
680 // - Status code is STATUS_VERIFY_REQUIRED and we are at APC level
681 // or higher, or within a guarded region. Can't wait for IO in
682 // the verify path in this case.
684 // Set the MORE_PROCESSING flag in the IrpContext to keep if from being
685 // deleted if this is a retryable condition.
688 // Note that (children of) CdFsdPostRequest can raise (Mdl allocation).
693 if (ExceptionCode
== STATUS_CANT_WAIT
) {
695 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
)) {
697 ExceptionCode
= CdFsdPostRequest( IrpContext
, Irp
);
700 else if ((ExceptionCode
== STATUS_VERIFY_REQUIRED
) &&
701 FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL
) &&
702 KeAreAllApcsDisabled()) {
704 ExceptionCode
= CdFsdPostRequest( IrpContext
, Irp
);
707 _SEH2_EXCEPT( CdExceptionFilter( IrpContext
, _SEH2_GetExceptionInformation() )) {
709 ExceptionCode
= _SEH2_GetExceptionCode();
712 // If we posted the request or our caller will retry then just return here.
715 if ((ExceptionCode
== STATUS_PENDING
) ||
716 (ExceptionCode
== STATUS_CANT_WAIT
)) {
718 return ExceptionCode
;
721 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_MORE_PROCESSING
);
724 // If we are not a top level request then we just complete the request
725 // with the current status code.
728 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL
)) {
730 CdCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
731 return ExceptionCode
;
735 // Store this error into the Irp for posting back to the Io system.
738 Irp
->IoStatus
.Status
= ExceptionCode
;
740 if (IoIsErrorUserInduced( ExceptionCode
)) {
743 // Check for the various error conditions that can be caused by,
744 // and possibly resolved my the user.
747 if (ExceptionCode
== STATUS_VERIFY_REQUIRED
) {
750 // Now we are at the top level file system entry point.
752 // If we have already posted this request then the device to
753 // verify is in the original thread. Find this via the Irp.
756 Device
= IoGetDeviceToVerify( Irp
->Tail
.Overlay
.Thread
);
757 IoSetDeviceToVerify( Irp
->Tail
.Overlay
.Thread
, NULL
);
760 // If there is no device in that location then check in the
764 if (Device
== NULL
) {
766 Device
= IoGetDeviceToVerify( PsGetCurrentThread() );
767 IoSetDeviceToVerify( PsGetCurrentThread(), NULL
);
769 NT_ASSERT( Device
!= NULL
);
774 // It turns out some storage drivers really do set invalid non-NULL device
775 // objects to verify.
777 // To work around this, completely ignore the device to verify in the thread,
778 // and just use our real device object instead.
781 if (IrpContext
->Vcb
) {
783 Device
= IrpContext
->Vcb
->Vpb
->RealDevice
;
787 // Let's not BugCheck just because the device to verify is somehow still NULL.
790 if (Device
== NULL
) {
792 ExceptionCode
= STATUS_DRIVER_INTERNAL_ERROR
;
794 CdCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
796 return ExceptionCode
;
800 // CdPerformVerify() will do the right thing with the Irp.
801 // If we return STATUS_CANT_WAIT then the current thread
802 // can retry the request.
805 return CdPerformVerify( IrpContext
, Irp
, Device
);
809 // The other user induced conditions generate an error unless
810 // they have been disabled for this request.
813 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_DISABLE_POPUPS
)) {
815 CdCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
817 return ExceptionCode
;
821 // Generate a pop-up.
825 if (IoGetCurrentIrpStackLocation( Irp
)->FileObject
!= NULL
) {
827 Vpb
= IoGetCurrentIrpStackLocation( Irp
)->FileObject
->Vpb
;
836 // The device to verify is either in my thread local storage
837 // or that of the thread that owns the Irp.
840 Thread
= Irp
->Tail
.Overlay
.Thread
;
841 Device
= IoGetDeviceToVerify( Thread
);
843 if (Device
== NULL
) {
845 Thread
= PsGetCurrentThread();
846 Device
= IoGetDeviceToVerify( Thread
);
848 NT_ASSERT( Device
!= NULL
);
852 // It turns out some storage drivers really do set invalid non-NULL device
853 // objects to verify.
855 // To work around this, completely ignore the device to verify in the thread,
856 // and just use our real device object instead.
859 if (IrpContext
->Vcb
) {
861 Device
= IrpContext
->Vcb
->Vpb
->RealDevice
;
865 // Let's not BugCheck just because the device to verify is somehow still NULL.
868 if (Device
== NULL
) {
870 CdCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
872 return ExceptionCode
;
876 // This routine actually causes the pop-up. It usually
877 // does this by queuing an APC to the callers thread,
878 // but in some cases it will complete the request immediately,
879 // so it is very important to IoMarkIrpPending() first.
882 IoMarkIrpPending( Irp
);
883 IoRaiseHardError( Irp
, Vpb
, Device
);
886 // We will be handing control back to the caller here, so
887 // reset the saved device object.
890 IoSetDeviceToVerify( Thread
, NULL
);
893 // The Irp will be completed by Io or resubmitted. In either
894 // case we must clean up the IrpContext here.
897 CdCompleteRequest( IrpContext
, NULL
, STATUS_SUCCESS
);
898 return STATUS_PENDING
;
903 // This is just a run of the mill error.
906 CdCompleteRequest( IrpContext
, Irp
, ExceptionCode
);
908 return ExceptionCode
;
914 _Inout_opt_ PIRP_CONTEXT IrpContext
,
915 _Inout_opt_ PIRP Irp
,
923 This routine completes a Irp and cleans up the IrpContext. Either or
924 both of these may not be specified.
928 Irp - Supplies the Irp being processed.
930 Status - Supplies the status to complete the Irp with
939 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext
);
940 ASSERT_OPTIONAL_IRP( Irp
);
943 // Cleanup the IrpContext if passed in here.
946 if (ARGUMENT_PRESENT( IrpContext
)) {
948 CdCleanupIrpContext( IrpContext
, FALSE
);
952 // If we have an Irp then complete the irp.
955 if (ARGUMENT_PRESENT( Irp
)) {
958 // Clear the information field in case we have used this Irp
962 if (NT_ERROR( Status
) &&
963 FlagOn( Irp
->Flags
, IRP_INPUT_OPERATION
)) {
965 Irp
->IoStatus
.Information
= 0;
968 Irp
->IoStatus
.Status
= Status
;
970 AssertVerifyDeviceIrp( Irp
);
972 IoCompleteRequest( Irp
, IO_CD_ROM_INCREMENT
);
981 _Inout_ PIRP_CONTEXT IrpContext
,
982 _In_ PTHREAD_CONTEXT ThreadContext
989 This routine is called at each Fsd/Fsp entry point set up the IrpContext
990 and thread local storage to track top level requests. If there is
991 not a Cdfs context in the thread local storage then we use the input one.
992 Otherwise we use the one already there. This routine also updates the
993 IrpContext based on the state of the top-level context.
995 If the TOP_LEVEL flag in the IrpContext is already set when we are called
996 then we force this request to appear top level.
1000 ThreadContext - Address on stack for local storage if not already present.
1002 ForceTopLevel - We force this request to appear top level regardless of
1003 any previous stack value.
1012 PTHREAD_CONTEXT CurrentThreadContext
;
1015 ULONG_PTR StackBottom
;
1020 ASSERT_IRP_CONTEXT( IrpContext
);
1023 // Get the current top-level irp out of the thread storage.
1024 // If NULL then this is the top-level request.
1027 CurrentThreadContext
= (PTHREAD_CONTEXT
) IoGetTopLevelIrp();
1029 if (CurrentThreadContext
== NULL
) {
1031 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL
);
1035 // Initialize the input context unless we are using the current
1036 // thread context block. We use the new block if our caller
1037 // specified this or the existing block is invalid.
1039 // The following must be true for the current to be a valid Cdfs context.
1041 // Structure must lie within current stack.
1042 // Address must be ULONG aligned.
1043 // Cdfs signature must be present.
1045 // If this is not a valid Cdfs context then use the input thread
1046 // context and store it in the top level context.
1050 IoGetStackLimits( &StackTop
, &StackBottom
);
1054 #pragma warning(suppress: 6011) // Bug in PREFast around bitflag operations
1056 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL
) ||
1058 (!IoWithinStackLimits( (ULONG_PTR
)CurrentThreadContext
, sizeof( THREAD_CONTEXT
) ) ||
1060 (((ULONG_PTR
) CurrentThreadContext
> StackBottom
- sizeof( THREAD_CONTEXT
)) ||
1061 ((ULONG_PTR
) CurrentThreadContext
<= StackTop
) ||
1063 FlagOn( (ULONG_PTR
) CurrentThreadContext
, 0x3 ) ||
1064 (CurrentThreadContext
->Cdfs
!= 0x53464443))) {
1066 ThreadContext
->Cdfs
= 0x53464443;
1067 ThreadContext
->SavedTopLevelIrp
= (PIRP
) CurrentThreadContext
;
1068 ThreadContext
->TopLevelIrpContext
= IrpContext
;
1069 IoSetTopLevelIrp( (PIRP
) ThreadContext
);
1071 IrpContext
->TopLevel
= IrpContext
;
1072 IrpContext
->ThreadContext
= ThreadContext
;
1074 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS
);
1077 // Otherwise use the IrpContext in the thread context.
1082 IrpContext
->TopLevel
= CurrentThreadContext
->TopLevelIrpContext
;
1089 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE
)
1090 _IRQL_requires_same_
1091 _Success_(return != FALSE
)
1093 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
1094 CdFastIoCheckIfPossible (
1095 _In_ PFILE_OBJECT FileObject
,
1096 _In_ PLARGE_INTEGER FileOffset
,
1100 _In_ BOOLEAN CheckForReadOperation
,
1102 _When_(return != FALSE
, _Post_equal_to_(_Old_(IoStatus
)))
1103 _When_(return == FALSE
, _Post_valid_
)
1104 PIO_STATUS_BLOCK IoStatus
,
1105 _In_ PDEVICE_OBJECT DeviceObject
1110 Routine Description:
1112 This routine checks if fast i/o is possible for a read/write operation
1116 FileObject - Supplies the file object used in the query
1118 FileOffset - Supplies the starting byte offset for the read/write operation
1120 Length - Supplies the length, in bytes, of the read/write operation
1122 Wait - Indicates if we can wait
1124 LockKey - Supplies the lock key
1126 CheckForReadOperation - Indicates if this is a check for a read or write
1129 IoStatus - Receives the status of the operation if our return value is
1134 BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
1135 to take the long route.
1141 TYPE_OF_OPEN TypeOfOpen
;
1142 LARGE_INTEGER LargeLength
;
1146 UNREFERENCED_PARAMETER( Wait
);
1147 UNREFERENCED_PARAMETER( DeviceObject
);
1150 // Decode the type of file object we're being asked to process and
1151 // make sure that is is only a user file open.
1154 TypeOfOpen
= CdFastDecodeFileObject( FileObject
, &Fcb
);
1156 if ((TypeOfOpen
!= UserFileOpen
) || !CheckForReadOperation
) {
1158 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
1162 LargeLength
.QuadPart
= Length
;
1165 // Check whether the file locks will allow for fast io.
1168 if ((Fcb
->FileLock
== NULL
) ||
1169 FsRtlFastCheckLockForRead( Fcb
->FileLock
,
1174 PsGetCurrentProcess() )) {
1185 _In_reads_bytes_(ByteCount
) PCHAR Buffer
,
1186 _In_ ULONG ByteCount
1190 Routine Description:
1192 This routine is called to generate a 32 bit serial number. This is
1193 done by doing four separate checksums into an array of bytes and
1194 then treating the bytes as a ULONG.
1198 Buffer - Pointer to the buffer to generate the ID for.
1200 ByteCount - Number of bytes in the buffer.
1204 ULONG - The 32 bit serial number.
1217 // Initialize the serial number.
1220 Checksum
.SerialId
= 0;
1223 // Continue while there are more bytes to use.
1226 while (ByteCount
--) {
1229 // Increment this sub-checksum.
1232 Checksum
.Bytes
[ByteCount
& 0x3] += *(Buffer
++);
1236 // Return the checksums as a ULONG.
1239 return Checksum
.SerialId
;