xref: /reactos/drivers/filesystems/cdfs/cddata.c (revision 34593d93)
1 
2 /*++
3 
4 Copyright (c) 1989-2000 Microsoft Corporation
5 
6 Module Name:
7 
8     CdData.c
9 
10 Abstract:
11 
12     This module declares the global data used by the Cdfs file system.
13 
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.
16 
17 
18 --*/
19 
20 #include "cdprocs.h"
21 
22 #ifdef CD_SANITY
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 };
30 #endif
31 
32 //
33 //  The Bug check file id for this module
34 //
35 
36 #define BugCheckFileId                   (CDFS_BUG_CHECK_CDDATA)
37 
38 //
39 //  Global data structures
40 //
41 
42 CD_DATA CdData;
43 FAST_IO_DISPATCH CdFastIoDispatch;
44 
45 //
46 //  Reserved directory strings.
47 //
48 
49 WCHAR CdUnicodeSelfArray[] = { L'.' };
50 WCHAR CdUnicodeParentArray[] = { L'.', L'.' };
51 
52 UNICODE_STRING CdUnicodeDirectoryNames[] = {
53     { 2, 2, CdUnicodeSelfArray},
54     { 4, 4, CdUnicodeParentArray}
55 };
56 
57 //
58 //  Volume descriptor identifier strings.
59 //
60 
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' };
64 
65 //
66 //  Volume label for audio disks.
67 //
68 
69 WCHAR CdAudioLabel[] = { L'A', L'u', L'd', L'i', L'o', L' ', L'C', L'D' };
70 USHORT CdAudioLabelLength = sizeof( CdAudioLabel );
71 
72 //
73 //  Pseudo file names for audio disks.
74 //
75 
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 );
81 
82 //
83 //  Escape sequences for mounting Unicode volumes.
84 //
85 
86 PCHAR CdJolietEscape[] = { "%/@", "%/C", "%/E" };
87 
88 //
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.
92 //
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.
96 //
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.
100 //
101 
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)
114 };
115 
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.
119 //
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.
122 //
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> )
125 //
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.
129 //
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.
134 //
135 
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
148 };
149 
150 //
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.
153 //
154 //  This header is added to all CD-XA files which are marked as having
155 //  mode2form2 sectors.
156 //
157 //  Fields marked 'ADJUST' need to be adjusted based on the size of the
158 //  data: Add file size to the marked DWORDS.
159 //
160 //  File Size of TRACK??.WAV = nSectors*2352 + sizeof(XAFileHeader)
161 //
162 //  RIFF('CDXA' FMT(Owner, Attr, 'X', 'A', FileNum, 0) data ( <CDXA Raw Data> )
163 //
164 
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
171     0,                                  // DWORD Owner ID
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
179 };
180 
181 #ifdef CDFS_TELEMETRY_DATA
182 
183 //
184 // Telemetry Data for reporting
185 //
186 
187 CDFS_TELEMETRY_DATA_CONTEXT CdTelemetryData;
188 
189 #endif // CDFS_TELEMETRY_DATA
190 
191 #ifdef ALLOC_PRAGMA
192 #pragma alloc_text(PAGE, CdFastIoCheckIfPossible)
193 #pragma alloc_text(PAGE, CdSerial32)
194 #pragma alloc_text(PAGE, CdSetThreadContext)
195 #endif
196 
197 _IRQL_requires_max_(APC_LEVEL)
__drv_dispatchType(DRIVER_DISPATCH)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)
213 NTSTATUS
214 NTAPI
215 CdFsdDispatch (
216     _In_ PDEVICE_OBJECT DeviceObject,
217     _Inout_ PIRP Irp
218     )
219 
220 /*++
221 
222 Routine Description:
223 
224     This is the driver entry to all of the Fsd dispatch points.
225 
226     Conceptually the Io routine will call this routine on all requests
227     to the file system.  We case on the type of request and invoke the
228     correct handler for this type of request.  There is an exception filter
229     to catch any exceptions in the CDFS code as well as the CDFS process
230     exception routine.
231 
232     This routine allocates and initializes the IrpContext for this request as
233     well as updating the top-level thread context as necessary.  We may loop
234     in this routine if we need to retry the request for any reason.  The
235     status code STATUS_CANT_WAIT is used to indicate this.  Suppose the disk
236     in the drive has changed.  An Fsd request will proceed normally until it
237     recognizes this condition.  STATUS_VERIFY_REQUIRED is raised at that point
238     and the exception code will handle the verify and either return
239     STATUS_CANT_WAIT or STATUS_PENDING depending on whether the request was
240     posted.
241 
242 Arguments:
243 
244     DeviceObject - Supplies the volume device object for this request
245 
246     Irp - Supplies the Irp being processed
247 
248 Return Value:
249 
250     NTSTATUS - The FSD status for the IRP
251 
252 --*/
253 
254 {
255     THREAD_CONTEXT ThreadContext = {0};
256     PIRP_CONTEXT IrpContext = NULL;
257     BOOLEAN Wait;
258 
259 #ifdef CD_SANITY
260     PVOID PreviousTopLevel;
261 #endif
262 
263     NTSTATUS Status;
264 
265 #if DBG
266 
267     KIRQL SaveIrql = KeGetCurrentIrql();
268 
269 #endif
270 
271     ASSERT_OPTIONAL_IRP( Irp );
272 
273     UNREFERENCED_PARAMETER( DeviceObject );
274 
275     FsRtlEnterFileSystem();
276 
277 #ifdef CD_SANITY
278     PreviousTopLevel = IoGetTopLevelIrp();
279 #endif
280 
281     //
282     //  Loop until this request has been completed or posted.
283     //
284 
285     do {
286 
287         //
288         //  Use a try-except to handle the exception cases.
289         //
290 
291         _SEH2_TRY {
292 
293             //
294             //  If the IrpContext is NULL then this is the first pass through
295             //  this loop.
296             //
297 
298             if (IrpContext == NULL) {
299 
300                 //
301                 //  Decide if this request is waitable an allocate the IrpContext.
302                 //  If the file object in the stack location is NULL then this
303                 //  is a mount which is always waitable.  Otherwise we look at
304                 //  the file object flags.
305                 //
306 
307                 if (IoGetCurrentIrpStackLocation( Irp )->FileObject == NULL) {
308 
309                     Wait = TRUE;
310 
311                 } else {
312 
313                     Wait = CanFsdWait( Irp );
314                 }
315 
316                 IrpContext = CdCreateIrpContext( Irp, Wait );
317 
318                 //
319                 //  Update the thread context information.
320                 //
321 
322                 CdSetThreadContext( IrpContext, &ThreadContext );
323 
324 #ifdef CD_SANITY
325                 NT_ASSERT( !CdTestTopLevel ||
326                         SafeNodeType( IrpContext->TopLevel ) == CDFS_NTC_IRP_CONTEXT );
327 #endif
328 
329             //
330             //  Otherwise cleanup the IrpContext for the retry.
331             //
332 
333             } else {
334 
335                 //
336                 //  Set the MORE_PROCESSING flag to make sure the IrpContext
337                 //  isn't inadvertently deleted here.  Then cleanup the
338                 //  IrpContext to perform the retry.
339                 //
340 
341                 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
342                 CdCleanupIrpContext( IrpContext, FALSE );
343             }
344 
345             //
346             //  Case on the major irp code.
347             //
348 
349             switch (IrpContext->MajorFunction) {
350 
351             case IRP_MJ_CREATE :
352 
353                 Status = CdCommonCreate( IrpContext, Irp );
354                 break;
355 
356             case IRP_MJ_CLOSE :
357 
358                 Status = CdCommonClose( IrpContext, Irp );
359                 break;
360 
361             case IRP_MJ_READ :
362 
363                 //
364                 //  If this is an Mdl complete request, don't go through
365                 //  common read.
366                 //
367 
368                 if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {
369 
370                     Status = CdCompleteMdl( IrpContext, Irp );
371 
372                 } else {
373 
374                     Status = CdCommonRead( IrpContext, Irp );
375                 }
376 
377                 break;
378 
379             case IRP_MJ_WRITE :
380 
381                 Status = CdCommonWrite( IrpContext, Irp );
382                 break;
383 
384             case IRP_MJ_QUERY_INFORMATION :
385 
386                 Status = CdCommonQueryInfo( IrpContext, Irp );
387                 break;
388 
389             case IRP_MJ_SET_INFORMATION :
390 
391                 Status = CdCommonSetInfo( IrpContext, Irp );
392                 break;
393 
394             case IRP_MJ_QUERY_VOLUME_INFORMATION :
395 
396                 Status = CdCommonQueryVolInfo( IrpContext, Irp );
397                 break;
398 
399             case IRP_MJ_DIRECTORY_CONTROL :
400 
401                 Status = CdCommonDirControl( IrpContext, Irp );
402                 break;
403 
404             case IRP_MJ_FILE_SYSTEM_CONTROL :
405 
406                 Status = CdCommonFsControl( IrpContext, Irp );
407                 break;
408 
409             case IRP_MJ_DEVICE_CONTROL :
410 
411                 Status = CdCommonDevControl( IrpContext, Irp );
412                 break;
413 
414             case IRP_MJ_LOCK_CONTROL :
415 
416                 Status = CdCommonLockControl( IrpContext, Irp );
417                 break;
418 
419             case IRP_MJ_CLEANUP :
420 
421                 Status = CdCommonCleanup( IrpContext, Irp );
422                 break;
423 
424             case IRP_MJ_PNP :
425 
426                 Status = CdCommonPnp( IrpContext, Irp );
427                 break;
428 
429             case IRP_MJ_SHUTDOWN :
430 
431                 Status = CdCommonShutdown( IrpContext, Irp );
432                 break;
433 
434             default :
435 
436                 Status = STATUS_INVALID_DEVICE_REQUEST;
437                 CdCompleteRequest( IrpContext, Irp, Status );
438             }
439 
440         } _SEH2_EXCEPT( CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
441 
442             Status = CdProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
443         } _SEH2_END;
444 
445     } while (Status == STATUS_CANT_WAIT);
446 
447 #ifdef CD_SANITY
448     NT_ASSERT( !CdTestTopLevel ||
449             (PreviousTopLevel == IoGetTopLevelIrp()) );
450 #endif
451 
452     FsRtlExitFileSystem();
453 
454     NT_ASSERT( SaveIrql == KeGetCurrentIrql( ));
455 
456     return Status;
457 }
458 
459 
460 #ifdef CD_SANITY
461 
462 VOID
CdRaiseStatusEx(_In_ PIRP_CONTEXT IrpContext,_In_ NTSTATUS Status,_In_ BOOLEAN NormalizeStatus,_In_opt_ ULONG FileId,_In_opt_ ULONG Line)463 CdRaiseStatusEx (
464     _In_ PIRP_CONTEXT IrpContext,
465     _In_ NTSTATUS Status,
466     _In_ BOOLEAN NormalizeStatus,
467     _In_opt_ ULONG FileId,
468     _In_opt_ ULONG Line
469     )
470 {
471     BOOLEAN BreakIn = FALSE;
472 
473     AssertVerifyDevice( IrpContext, Status);
474 
475     if (CdTraceRaises)  {
476 
477         DbgPrint( "%p CdRaiseStatusEx 0x%x @ fid %d, line %d\n", PsGetCurrentThread(), Status, FileId, Line);
478     }
479 
480     if (CdTestRaisedStatus && !CdBreakOnAnyRaise)  {
481 
482         ULONG Index;
483 
484         for (Index = 0;
485              Index < (sizeof( CdInterestingExceptionCodes) / sizeof( CdInterestingExceptionCodes[0]));
486              Index++)  {
487 
488             if ((STATUS_SUCCESS != CdInterestingExceptionCodes[Index]) &&
489                 (CdInterestingExceptionCodes[Index] == Status))  {
490 
491                 BreakIn = TRUE;
492                 break;
493             }
494         }
495     }
496 
497     if (BreakIn || CdBreakOnAnyRaise)  {
498 
499         DbgPrint( "CDFS: Breaking on raised status %08x  (BI=%d,BA=%d)\n", Status, BreakIn, CdBreakOnAnyRaise);
500         DbgPrint( "CDFS: (FILEID %d LINE %d)\n", FileId, Line);
501         DbgPrint( "CDFS: Contact CDFS.SYS component owner for triage.\n");
502         DbgPrint( "CDFS: 'eb %p 0;eb %p 0' to disable this alert.\n", &CdTestRaisedStatus, &CdBreakOnAnyRaise);
503 
504         NT_ASSERT(FALSE);
505     }
506 
507     if (NormalizeStatus)  {
508 
509         IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR);
510     }
511     else {
512 
513         IrpContext->ExceptionStatus = Status;
514     }
515 
516     IrpContext->RaisedAtLineFile = (FileId << 16) | Line;
517 
518     ExRaiseStatus( IrpContext->ExceptionStatus);
519 }
520 
521 #endif
522 
523 
524 LONG
CdExceptionFilter(_Inout_ PIRP_CONTEXT IrpContext,_In_ PEXCEPTION_POINTERS ExceptionPointer)525 CdExceptionFilter (
526     _Inout_ PIRP_CONTEXT IrpContext,
527     _In_ PEXCEPTION_POINTERS ExceptionPointer
528     )
529 
530 /*++
531 
532 Routine Description:
533 
534     This routine is used to decide whether we will handle a raised exception
535     status.  If CDFS explicitly raised an error then this status is already
536     in the IrpContext.  We choose which is the correct status code and
537     either indicate that we will handle the exception or bug-check the system.
538 
539 Arguments:
540 
541     ExceptionCode - Supplies the exception code to being checked.
542 
543 Return Value:
544 
545     ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
546 
547 --*/
548 
549 {
550     NTSTATUS ExceptionCode;
551     BOOLEAN TestStatus = TRUE;
552 
553     ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
554 
555     ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
556 
557     //
558     // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
559     // from the exception record.
560     //
561 
562     if ((ExceptionCode == STATUS_IN_PAGE_ERROR) &&
563         (ExceptionPointer->ExceptionRecord->NumberParameters >= 3)) {
564 
565         ExceptionCode =
566             (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
567     }
568 
569     //
570     //  If there is an Irp context then check which status code to use.
571     //
572 
573     if (ARGUMENT_PRESENT( IrpContext )) {
574 
575         if (IrpContext->ExceptionStatus == STATUS_SUCCESS) {
576 
577             //
578             //  Store the real status into the IrpContext.
579             //
580 
581             IrpContext->ExceptionStatus = ExceptionCode;
582 
583         } else {
584 
585             //
586             //  No need to test the status code if we raised it ourselves.
587             //
588 
589             TestStatus = FALSE;
590         }
591     }
592 
593     AssertVerifyDevice( IrpContext, IrpContext->ExceptionStatus );
594 
595     //
596     //  Bug check if this status is not supported.
597     //
598 
599     if (TestStatus && !FsRtlIsNtstatusExpected( ExceptionCode )) {
600 
601 #ifdef _MSC_VER
602 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "We're corrupted." )
603 #endif
604         CdBugCheck( (ULONG_PTR) ExceptionPointer->ExceptionRecord,
605                     (ULONG_PTR) ExceptionPointer->ContextRecord,
606                     (ULONG_PTR) ExceptionPointer->ExceptionRecord->ExceptionAddress );
607 
608     }
609 
610     return EXCEPTION_EXECUTE_HANDLER;
611 }
612 
613 
614 
_Requires_lock_held_(_Global_critical_region_)615 _Requires_lock_held_(_Global_critical_region_)
616 NTSTATUS
617 CdProcessException (
618     _In_opt_ PIRP_CONTEXT IrpContext,
619     _Inout_ PIRP Irp,
620     _In_ NTSTATUS ExceptionCode
621     )
622 
623 /*++
624 
625 Routine Description:
626 
627     This routine processes an exception.  It either completes the request
628     with the exception status in the IrpContext, sends this off to the Fsp
629     workque or causes it to be retried in the current thread if a verification
630     is needed.
631 
632     If the volume needs to be verified (STATUS_VERIFY_REQUIRED) and we can
633     do the work in the current thread we will translate the status code
634     to STATUS_CANT_WAIT to indicate that we need to retry the request.
635 
636 Arguments:
637 
638     Irp - Supplies the Irp being processed
639 
640     ExceptionCode - Supplies the normalized exception status being handled
641 
642 Return Value:
643 
644     NTSTATUS - Returns the results of either posting the Irp or the
645         saved completion status.
646 
647 --*/
648 
649 {
650     PDEVICE_OBJECT Device = NULL;
651     PVPB Vpb;
652     PETHREAD Thread;
653 
654     ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
655     ASSERT_IRP( Irp );
656 
657     //
658     //  If there is not an irp context, then complete the request with the
659     //  current status code.
660     //
661 
662     if (!ARGUMENT_PRESENT( IrpContext )) {
663 
664         CdCompleteRequest( NULL, Irp, ExceptionCode );
665         return ExceptionCode;
666     }
667 
668     //
669     //  Get the real exception status from the IrpContext.
670     //
671 
672     ExceptionCode = IrpContext->ExceptionStatus;
673 
674     //
675     //  Check if we are posting this request.  One of the following must be true
676     //  if we are to post a request.
677     //
678     //      - Status code is STATUS_CANT_WAIT and the request is asynchronous
679     //          or we are forcing this to be posted.
680     //
681     //      - Status code is STATUS_VERIFY_REQUIRED and we are at APC level
682     //          or higher, or within a guarded region.  Can't wait for IO in
683     //          the verify path in this case.
684     //
685     //  Set the MORE_PROCESSING flag in the IrpContext to keep if from being
686     //  deleted if this is a retryable condition.
687     //
688     //
689     //  Note that (children of) CdFsdPostRequest can raise (Mdl allocation).
690     //
691 
692     _SEH2_TRY {
693 
694         if (ExceptionCode == STATUS_CANT_WAIT) {
695 
696             if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST )) {
697 
698                 ExceptionCode = CdFsdPostRequest( IrpContext, Irp );
699             }
700         }
701         else if ((ExceptionCode == STATUS_VERIFY_REQUIRED) &&
702                  FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) &&
703                  KeAreAllApcsDisabled()) {
704 
705             ExceptionCode = CdFsdPostRequest( IrpContext, Irp );
706         }
707     }
708     _SEH2_EXCEPT( CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() ))  {
709 
710         ExceptionCode = _SEH2_GetExceptionCode();
711     } _SEH2_END;
712     //
713     //  If we posted the request or our caller will retry then just return here.
714     //
715 
716     if ((ExceptionCode == STATUS_PENDING) ||
717         (ExceptionCode == STATUS_CANT_WAIT)) {
718 
719         return ExceptionCode;
720     }
721 
722     ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
723 
724     //
725     //  If we are not a top level request then we just complete the request
726     //  with the current status code.
727     //
728 
729     if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
730 
731         CdCompleteRequest( IrpContext, Irp, ExceptionCode );
732         return ExceptionCode;
733     }
734 
735     //
736     //  Store this error into the Irp for posting back to the Io system.
737     //
738 
739     Irp->IoStatus.Status = ExceptionCode;
740 
741     if (IoIsErrorUserInduced( ExceptionCode )) {
742 
743         //
744         //  Check for the various error conditions that can be caused by,
745         //  and possibly resolved my the user.
746         //
747 
748         if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
749 
750             //
751             //  Now we are at the top level file system entry point.
752             //
753             //  If we have already posted this request then the device to
754             //  verify is in the original thread.  Find this via the Irp.
755             //
756 
757             Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
758             IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
759 
760             //
761             //  If there is no device in that location then check in the
762             //  current thread.
763             //
764 
765             if (Device == NULL) {
766 
767                 Device = IoGetDeviceToVerify( PsGetCurrentThread() );
768                 IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
769 
770                 NT_ASSERT( Device != NULL );
771 
772             }
773 
774             //
775             //  It turns out some storage drivers really do set invalid non-NULL device
776             //  objects to verify.
777             //
778             //  To work around this, completely ignore the device to verify in the thread,
779             //  and just use our real device object instead.
780             //
781 
782             if (IrpContext->Vcb) {
783 
784                 Device = IrpContext->Vcb->Vpb->RealDevice;
785             }
786 
787             //
788             //  Let's not BugCheck just because the device to verify is somehow still NULL.
789             //
790 
791             if (Device == NULL) {
792 
793                 ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
794 
795                 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
796 
797                 return ExceptionCode;
798             }
799 
800             //
801             //  CdPerformVerify() will do the right thing with the Irp.
802             //  If we return STATUS_CANT_WAIT then the current thread
803             //  can retry the request.
804             //
805 
806             return CdPerformVerify( IrpContext, Irp, Device );
807         }
808 
809         //
810         //  The other user induced conditions generate an error unless
811         //  they have been disabled for this request.
812         //
813 
814         if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS )) {
815 
816             CdCompleteRequest( IrpContext, Irp, ExceptionCode );
817 
818             return ExceptionCode;
819 
820         }
821         //
822         //  Generate a pop-up.
823         //
824         else {
825 
826             if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) {
827 
828                 Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb;
829 
830             } else {
831 
832                 Vpb = NULL;
833             }
834 
835 
836             //
837             //  The device to verify is either in my thread local storage
838             //  or that of the thread that owns the Irp.
839             //
840 
841             Thread = Irp->Tail.Overlay.Thread;
842             Device = IoGetDeviceToVerify( Thread );
843 
844             if (Device == NULL) {
845 
846                 Thread = PsGetCurrentThread();
847                 Device = IoGetDeviceToVerify( Thread );
848 
849                 NT_ASSERT( Device != NULL );
850             }
851 
852             //
853             //  It turns out some storage drivers really do set invalid non-NULL device
854             //  objects to verify.
855             //
856             //  To work around this, completely ignore the device to verify in the thread,
857             //  and just use our real device object instead.
858             //
859 
860             if (IrpContext->Vcb) {
861 
862                 Device = IrpContext->Vcb->Vpb->RealDevice;
863             }
864 
865             //
866             //  Let's not BugCheck just because the device to verify is somehow still NULL.
867             //
868 
869             if (Device == NULL) {
870 
871                 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
872 
873                 return ExceptionCode;
874             }
875 
876             //
877             //  This routine actually causes the pop-up.  It usually
878             //  does this by queuing an APC to the callers thread,
879             //  but in some cases it will complete the request immediately,
880             //  so it is very important to IoMarkIrpPending() first.
881             //
882 
883             IoMarkIrpPending( Irp );
884             IoRaiseHardError( Irp, Vpb, Device );
885 
886             //
887             //  We will be handing control back to the caller here, so
888             //  reset the saved device object.
889             //
890 
891             IoSetDeviceToVerify( Thread, NULL );
892 
893             //
894             //  The Irp will be completed by Io or resubmitted.  In either
895             //  case we must clean up the IrpContext here.
896             //
897 
898             CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
899             return STATUS_PENDING;
900         }
901     }
902 
903     //
904     //  This is just a run of the mill error.
905     //
906 
907     CdCompleteRequest( IrpContext, Irp, ExceptionCode );
908 
909     return ExceptionCode;
910 }
911 
912 
913 VOID
CdCompleteRequest(_Inout_opt_ PIRP_CONTEXT IrpContext,_Inout_opt_ PIRP Irp,_In_ NTSTATUS Status)914 CdCompleteRequest (
915     _Inout_opt_ PIRP_CONTEXT IrpContext,
916     _Inout_opt_ PIRP Irp,
917     _In_ NTSTATUS Status
918     )
919 
920 /*++
921 
922 Routine Description:
923 
924     This routine completes a Irp and cleans up the IrpContext.  Either or
925     both of these may not be specified.
926 
927 Arguments:
928 
929     Irp - Supplies the Irp being processed.
930 
931     Status - Supplies the status to complete the Irp with
932 
933 Return Value:
934 
935     None.
936 
937 --*/
938 
939 {
940     ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
941     ASSERT_OPTIONAL_IRP( Irp );
942 
943     //
944     //  Cleanup the IrpContext if passed in here.
945     //
946 
947     if (ARGUMENT_PRESENT( IrpContext )) {
948 
949         CdCleanupIrpContext( IrpContext, FALSE );
950     }
951 
952     //
953     //  If we have an Irp then complete the irp.
954     //
955 
956     if (ARGUMENT_PRESENT( Irp )) {
957 
958         //
959         //  Clear the information field in case we have used this Irp
960         //  internally.
961         //
962 
963         if (NT_ERROR( Status ) &&
964             FlagOn( Irp->Flags, IRP_INPUT_OPERATION )) {
965 
966             Irp->IoStatus.Information = 0;
967         }
968 
969         Irp->IoStatus.Status = Status;
970 
971         AssertVerifyDeviceIrp( Irp );
972 
973         IoCompleteRequest( Irp, IO_CD_ROM_INCREMENT );
974     }
975 
976     return;
977 }
978 
979 
980 VOID
CdSetThreadContext(_Inout_ PIRP_CONTEXT IrpContext,_In_ PTHREAD_CONTEXT ThreadContext)981 CdSetThreadContext (
982     _Inout_ PIRP_CONTEXT IrpContext,
983     _In_ PTHREAD_CONTEXT ThreadContext
984     )
985 
986 /*++
987 
988 Routine Description:
989 
990     This routine is called at each Fsd/Fsp entry point set up the IrpContext
991     and thread local storage to track top level requests.  If there is
992     not a Cdfs context in the thread local storage then we use the input one.
993     Otherwise we use the one already there.  This routine also updates the
994     IrpContext based on the state of the top-level context.
995 
996     If the TOP_LEVEL flag in the IrpContext is already set when we are called
997     then we force this request to appear top level.
998 
999 Arguments:
1000 
1001     ThreadContext - Address on stack for local storage if not already present.
1002 
1003     ForceTopLevel - We force this request to appear top level regardless of
1004         any previous stack value.
1005 
1006 Return Value:
1007 
1008     None
1009 
1010 --*/
1011 
1012 {
1013     PTHREAD_CONTEXT CurrentThreadContext;
1014 #ifdef __REACTOS__
1015     ULONG_PTR StackTop;
1016     ULONG_PTR StackBottom;
1017 #endif
1018 
1019     PAGED_CODE();
1020 
1021     ASSERT_IRP_CONTEXT( IrpContext );
1022 
1023     //
1024     //  Get the current top-level irp out of the thread storage.
1025     //  If NULL then this is the top-level request.
1026     //
1027 
1028     CurrentThreadContext = (PTHREAD_CONTEXT) IoGetTopLevelIrp();
1029 
1030     if (CurrentThreadContext == NULL) {
1031 
1032         SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL );
1033     }
1034 
1035     //
1036     //  Initialize the input context unless we are using the current
1037     //  thread context block.  We use the new block if our caller
1038     //  specified this or the existing block is invalid.
1039     //
1040     //  The following must be true for the current to be a valid Cdfs context.
1041     //
1042     //      Structure must lie within current stack.
1043     //      Address must be ULONG aligned.
1044     //      Cdfs signature must be present.
1045     //
1046     //  If this is not a valid Cdfs context then use the input thread
1047     //  context and store it in the top level context.
1048     //
1049 
1050 #ifdef __REACTOS__
1051     IoGetStackLimits( &StackTop, &StackBottom);
1052 #endif
1053 
1054 #ifdef _MSC_VER
1055 #pragma warning(suppress: 6011) // Bug in PREFast around bitflag operations
1056 #endif
1057     if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) ||
1058 #ifndef __REACTOS__
1059         (!IoWithinStackLimits( (ULONG_PTR)CurrentThreadContext, sizeof( THREAD_CONTEXT ) ) ||
1060 #else
1061         (((ULONG_PTR) CurrentThreadContext > StackBottom - sizeof( THREAD_CONTEXT )) ||
1062          ((ULONG_PTR) CurrentThreadContext <= StackTop) ||
1063 #endif
1064          FlagOn( (ULONG_PTR) CurrentThreadContext, 0x3 ) ||
1065          (CurrentThreadContext->Cdfs != 0x53464443))) {
1066 
1067         ThreadContext->Cdfs = 0x53464443;
1068         ThreadContext->SavedTopLevelIrp = (PIRP) CurrentThreadContext;
1069         ThreadContext->TopLevelIrpContext = IrpContext;
1070         IoSetTopLevelIrp( (PIRP) ThreadContext );
1071 
1072         IrpContext->TopLevel = IrpContext;
1073         IrpContext->ThreadContext = ThreadContext;
1074 
1075         SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS );
1076 
1077     //
1078     //  Otherwise use the IrpContext in the thread context.
1079     //
1080 
1081     } else {
1082 
1083         IrpContext->TopLevel = CurrentThreadContext->TopLevelIrpContext;
1084     }
1085 
1086     return;
1087 }
1088 
1089 
_Function_class_(FAST_IO_CHECK_IF_POSSIBLE)1090 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE)
1091 _IRQL_requires_same_
1092 _Success_(return != FALSE)
1093 BOOLEAN
1094 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1095 CdFastIoCheckIfPossible (
1096     _In_ PFILE_OBJECT FileObject,
1097     _In_ PLARGE_INTEGER FileOffset,
1098     _In_ ULONG Length,
1099     _In_ BOOLEAN Wait,
1100     _In_ ULONG LockKey,
1101     _In_ BOOLEAN CheckForReadOperation,
1102     _Pre_notnull_
1103     _When_(return != FALSE, _Post_equal_to_(_Old_(IoStatus)))
1104     _When_(return == FALSE, _Post_valid_)
1105     PIO_STATUS_BLOCK IoStatus,
1106     _In_ PDEVICE_OBJECT DeviceObject
1107     )
1108 
1109 /*++
1110 
1111 Routine Description:
1112 
1113     This routine checks if fast i/o is possible for a read/write operation
1114 
1115 Arguments:
1116 
1117     FileObject - Supplies the file object used in the query
1118 
1119     FileOffset - Supplies the starting byte offset for the read/write operation
1120 
1121     Length - Supplies the length, in bytes, of the read/write operation
1122 
1123     Wait - Indicates if we can wait
1124 
1125     LockKey - Supplies the lock key
1126 
1127     CheckForReadOperation - Indicates if this is a check for a read or write
1128         operation
1129 
1130     IoStatus - Receives the status of the operation if our return value is
1131         FastIoReturnError
1132 
1133 Return Value:
1134 
1135     BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
1136         to take the long route.
1137 
1138 --*/
1139 
1140 {
1141     PFCB Fcb;
1142     TYPE_OF_OPEN TypeOfOpen;
1143     LARGE_INTEGER LargeLength;
1144 
1145     PAGED_CODE();
1146 
1147     UNREFERENCED_PARAMETER( Wait );
1148     UNREFERENCED_PARAMETER( DeviceObject );
1149 
1150     //
1151     //  Decode the type of file object we're being asked to process and
1152     //  make sure that is is only a user file open.
1153     //
1154 
1155     TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
1156 
1157     if ((TypeOfOpen != UserFileOpen) || !CheckForReadOperation) {
1158 
1159         IoStatus->Status = STATUS_INVALID_PARAMETER;
1160         return TRUE;
1161     }
1162 
1163     LargeLength.QuadPart = Length;
1164 
1165     //
1166     //  Check whether the file locks will allow for fast io.
1167     //
1168 
1169     if ((Fcb->FileLock == NULL) ||
1170         FsRtlFastCheckLockForRead( Fcb->FileLock,
1171                                    FileOffset,
1172                                    &LargeLength,
1173                                    LockKey,
1174                                    FileObject,
1175                                    PsGetCurrentProcess() )) {
1176 
1177         return TRUE;
1178     }
1179 
1180     return FALSE;
1181 }
1182 
1183 
1184 ULONG
CdSerial32(_In_reads_bytes_ (ByteCount)PCHAR Buffer,_In_ ULONG ByteCount)1185 CdSerial32 (
1186     _In_reads_bytes_(ByteCount) PCHAR Buffer,
1187     _In_ ULONG ByteCount
1188     )
1189 /*++
1190 
1191 Routine Description:
1192 
1193     This routine is called to generate a 32 bit serial number.  This is
1194     done by doing four separate checksums into an array of bytes and
1195     then treating the bytes as a ULONG.
1196 
1197 Arguments:
1198 
1199     Buffer - Pointer to the buffer to generate the ID for.
1200 
1201     ByteCount - Number of bytes in the buffer.
1202 
1203 Return Value:
1204 
1205     ULONG - The 32 bit serial number.
1206 
1207 --*/
1208 
1209 {
1210     union {
1211         UCHAR   Bytes[4];
1212         ULONG   SerialId;
1213     } Checksum;
1214 
1215     PAGED_CODE();
1216 
1217     //
1218     //  Initialize the serial number.
1219     //
1220 
1221     Checksum.SerialId = 0;
1222 
1223     //
1224     //  Continue while there are more bytes to use.
1225     //
1226 
1227     while (ByteCount--) {
1228 
1229         //
1230         //  Increment this sub-checksum.
1231         //
1232 
1233         Checksum.Bytes[ByteCount & 0x3] += *(Buffer++);
1234     }
1235 
1236     //
1237     //  Return the checksums as a ULONG.
1238     //
1239 
1240     return Checksum.SerialId;
1241 }
1242 
1243 
1244