[CDFS_NEW] Re-apply many of the reactos-specific changes and fix build.
[reactos.git] / drivers / filesystems / cdfs_new / cddata.c
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)
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 CdFsdDispatch (
215 _In_ PDEVICE_OBJECT DeviceObject,
216 _Inout_ PIRP Irp
217 )
218
219 /*++
220
221 Routine Description:
222
223 This is the driver entry to all of the Fsd dispatch points.
224
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
229 exception routine.
230
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
239 posted.
240
241 Arguments:
242
243 DeviceObject - Supplies the volume device object for this request
244
245 Irp - Supplies the Irp being processed
246
247 Return Value:
248
249 NTSTATUS - The FSD status for the IRP
250
251 --*/
252
253 {
254 THREAD_CONTEXT ThreadContext = {0};
255 PIRP_CONTEXT IrpContext = NULL;
256 BOOLEAN Wait;
257
258 #ifdef CD_SANITY
259 PVOID PreviousTopLevel;
260 #endif
261
262 NTSTATUS Status;
263
264 #if DBG
265
266 KIRQL SaveIrql = KeGetCurrentIrql();
267
268 #endif
269
270 ASSERT_OPTIONAL_IRP( Irp );
271
272 UNREFERENCED_PARAMETER( DeviceObject );
273
274 FsRtlEnterFileSystem();
275
276 #ifdef CD_SANITY
277 PreviousTopLevel = IoGetTopLevelIrp();
278 #endif
279
280 //
281 // Loop until this request has been completed or posted.
282 //
283
284 do {
285
286 //
287 // Use a try-except to handle the exception cases.
288 //
289
290 _SEH2_TRY {
291
292 //
293 // If the IrpContext is NULL then this is the first pass through
294 // this loop.
295 //
296
297 if (IrpContext == NULL) {
298
299 //
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.
304 //
305
306 if (IoGetCurrentIrpStackLocation( Irp )->FileObject == NULL) {
307
308 Wait = TRUE;
309
310 } else {
311
312 Wait = CanFsdWait( Irp );
313 }
314
315 IrpContext = CdCreateIrpContext( Irp, Wait );
316
317 //
318 // Update the thread context information.
319 //
320
321 CdSetThreadContext( IrpContext, &ThreadContext );
322
323 #ifdef CD_SANITY
324 NT_ASSERT( !CdTestTopLevel ||
325 SafeNodeType( IrpContext->TopLevel ) == CDFS_NTC_IRP_CONTEXT );
326 #endif
327
328 //
329 // Otherwise cleanup the IrpContext for the retry.
330 //
331
332 } else {
333
334 //
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.
338 //
339
340 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
341 CdCleanupIrpContext( IrpContext, FALSE );
342 }
343
344 //
345 // Case on the major irp code.
346 //
347
348 switch (IrpContext->MajorFunction) {
349
350 case IRP_MJ_CREATE :
351
352 Status = CdCommonCreate( IrpContext, Irp );
353 break;
354
355 case IRP_MJ_CLOSE :
356
357 Status = CdCommonClose( IrpContext, Irp );
358 break;
359
360 case IRP_MJ_READ :
361
362 //
363 // If this is an Mdl complete request, don't go through
364 // common read.
365 //
366
367 if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {
368
369 Status = CdCompleteMdl( IrpContext, Irp );
370
371 } else {
372
373 Status = CdCommonRead( IrpContext, Irp );
374 }
375
376 break;
377
378 case IRP_MJ_WRITE :
379
380 Status = CdCommonWrite( IrpContext, Irp );
381 break;
382
383 case IRP_MJ_QUERY_INFORMATION :
384
385 Status = CdCommonQueryInfo( IrpContext, Irp );
386 break;
387
388 case IRP_MJ_SET_INFORMATION :
389
390 Status = CdCommonSetInfo( IrpContext, Irp );
391 break;
392
393 case IRP_MJ_QUERY_VOLUME_INFORMATION :
394
395 Status = CdCommonQueryVolInfo( IrpContext, Irp );
396 break;
397
398 case IRP_MJ_DIRECTORY_CONTROL :
399
400 Status = CdCommonDirControl( IrpContext, Irp );
401 break;
402
403 case IRP_MJ_FILE_SYSTEM_CONTROL :
404
405 Status = CdCommonFsControl( IrpContext, Irp );
406 break;
407
408 case IRP_MJ_DEVICE_CONTROL :
409
410 Status = CdCommonDevControl( IrpContext, Irp );
411 break;
412
413 case IRP_MJ_LOCK_CONTROL :
414
415 Status = CdCommonLockControl( IrpContext, Irp );
416 break;
417
418 case IRP_MJ_CLEANUP :
419
420 Status = CdCommonCleanup( IrpContext, Irp );
421 break;
422
423 case IRP_MJ_PNP :
424
425 Status = CdCommonPnp( IrpContext, Irp );
426 break;
427
428 case IRP_MJ_SHUTDOWN :
429
430 Status = CdCommonShutdown( IrpContext, Irp );
431 break;
432
433 default :
434
435 Status = STATUS_INVALID_DEVICE_REQUEST;
436 CdCompleteRequest( IrpContext, Irp, Status );
437 }
438
439 } _SEH2_EXCEPT( CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
440
441 Status = CdProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
442 } _SEH2_END;
443
444 } while (Status == STATUS_CANT_WAIT);
445
446 #ifdef CD_SANITY
447 NT_ASSERT( !CdTestTopLevel ||
448 (PreviousTopLevel == IoGetTopLevelIrp()) );
449 #endif
450
451 FsRtlExitFileSystem();
452
453 NT_ASSERT( SaveIrql == KeGetCurrentIrql( ));
454
455 return Status;
456 }
457
458
459 #ifdef CD_SANITY
460
461 VOID
462 CdRaiseStatusEx (
463 _In_ PIRP_CONTEXT IrpContext,
464 _In_ NTSTATUS Status,
465 _In_ BOOLEAN NormalizeStatus,
466 _In_opt_ ULONG FileId,
467 _In_opt_ ULONG Line
468 )
469 {
470 BOOLEAN BreakIn = FALSE;
471
472 AssertVerifyDevice( IrpContext, Status);
473
474 if (CdTraceRaises) {
475
476 DbgPrint( "%p CdRaiseStatusEx 0x%x @ fid %d, line %d\n", PsGetCurrentThread(), Status, FileId, Line);
477 }
478
479 if (CdTestRaisedStatus && !CdBreakOnAnyRaise) {
480
481 ULONG Index;
482
483 for (Index = 0;
484 Index < (sizeof( CdInterestingExceptionCodes) / sizeof( CdInterestingExceptionCodes[0]));
485 Index++) {
486
487 if ((STATUS_SUCCESS != CdInterestingExceptionCodes[Index]) &&
488 (CdInterestingExceptionCodes[Index] == Status)) {
489
490 BreakIn = TRUE;
491 break;
492 }
493 }
494 }
495
496 if (BreakIn || CdBreakOnAnyRaise) {
497
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);
502
503 NT_ASSERT(FALSE);
504 }
505
506 if (NormalizeStatus) {
507
508 IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR);
509 }
510 else {
511
512 IrpContext->ExceptionStatus = Status;
513 }
514
515 IrpContext->RaisedAtLineFile = (FileId << 16) | Line;
516
517 ExRaiseStatus( IrpContext->ExceptionStatus);
518 }
519
520 #endif
521
522
523 LONG
524 CdExceptionFilter (
525 _Inout_ PIRP_CONTEXT IrpContext,
526 _In_ PEXCEPTION_POINTERS ExceptionPointer
527 )
528
529 /*++
530
531 Routine Description:
532
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.
537
538 Arguments:
539
540 ExceptionCode - Supplies the exception code to being checked.
541
542 Return Value:
543
544 ULONG - returns EXCEPTION_EXECUTE_HANDLER or bugchecks
545
546 --*/
547
548 {
549 NTSTATUS ExceptionCode;
550 BOOLEAN TestStatus = TRUE;
551
552 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
553
554 ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
555
556 //
557 // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code
558 // from the exception record.
559 //
560
561 if ((ExceptionCode == STATUS_IN_PAGE_ERROR) &&
562 (ExceptionPointer->ExceptionRecord->NumberParameters >= 3)) {
563
564 ExceptionCode =
565 (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2];
566 }
567
568 //
569 // If there is an Irp context then check which status code to use.
570 //
571
572 if (ARGUMENT_PRESENT( IrpContext )) {
573
574 if (IrpContext->ExceptionStatus == STATUS_SUCCESS) {
575
576 //
577 // Store the real status into the IrpContext.
578 //
579
580 IrpContext->ExceptionStatus = ExceptionCode;
581
582 } else {
583
584 //
585 // No need to test the status code if we raised it ourselves.
586 //
587
588 TestStatus = FALSE;
589 }
590 }
591
592 AssertVerifyDevice( IrpContext, IrpContext->ExceptionStatus );
593
594 //
595 // Bug check if this status is not supported.
596 //
597
598 if (TestStatus && !FsRtlIsNtstatusExpected( ExceptionCode )) {
599
600 #ifdef _MSC_VER
601 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "We're corrupted." )
602 #endif
603 CdBugCheck( (ULONG_PTR) ExceptionPointer->ExceptionRecord,
604 (ULONG_PTR) ExceptionPointer->ContextRecord,
605 (ULONG_PTR) ExceptionPointer->ExceptionRecord->ExceptionAddress );
606
607 }
608
609 return EXCEPTION_EXECUTE_HANDLER;
610 }
611
612 \f
613
614 _Requires_lock_held_(_Global_critical_region_)
615 NTSTATUS
616 CdProcessException (
617 _In_opt_ PIRP_CONTEXT IrpContext,
618 _Inout_ PIRP Irp,
619 _In_ NTSTATUS ExceptionCode
620 )
621
622 /*++
623
624 Routine Description:
625
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
629 is needed.
630
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.
634
635 Arguments:
636
637 Irp - Supplies the Irp being processed
638
639 ExceptionCode - Supplies the normalized exception status being handled
640
641 Return Value:
642
643 NTSTATUS - Returns the results of either posting the Irp or the
644 saved completion status.
645
646 --*/
647
648 {
649 PDEVICE_OBJECT Device = NULL;
650 PVPB Vpb;
651 PETHREAD Thread;
652
653 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
654 ASSERT_IRP( Irp );
655
656 //
657 // If there is not an irp context, then complete the request with the
658 // current status code.
659 //
660
661 if (!ARGUMENT_PRESENT( IrpContext )) {
662
663 CdCompleteRequest( NULL, Irp, ExceptionCode );
664 return ExceptionCode;
665 }
666
667 //
668 // Get the real exception status from the IrpContext.
669 //
670
671 ExceptionCode = IrpContext->ExceptionStatus;
672
673 //
674 // Check if we are posting this request. One of the following must be true
675 // if we are to post a request.
676 //
677 // - Status code is STATUS_CANT_WAIT and the request is asynchronous
678 // or we are forcing this to be posted.
679 //
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.
683 //
684 // Set the MORE_PROCESSING flag in the IrpContext to keep if from being
685 // deleted if this is a retryable condition.
686 //
687 //
688 // Note that (children of) CdFsdPostRequest can raise (Mdl allocation).
689 //
690
691 _SEH2_TRY {
692
693 if (ExceptionCode == STATUS_CANT_WAIT) {
694
695 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST )) {
696
697 ExceptionCode = CdFsdPostRequest( IrpContext, Irp );
698 }
699 }
700 else if ((ExceptionCode == STATUS_VERIFY_REQUIRED) &&
701 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) &&
702 KeAreAllApcsDisabled()) {
703
704 ExceptionCode = CdFsdPostRequest( IrpContext, Irp );
705 }
706 }
707 _SEH2_EXCEPT( CdExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
708
709 ExceptionCode = _SEH2_GetExceptionCode();
710 } _SEH2_END;
711 //
712 // If we posted the request or our caller will retry then just return here.
713 //
714
715 if ((ExceptionCode == STATUS_PENDING) ||
716 (ExceptionCode == STATUS_CANT_WAIT)) {
717
718 return ExceptionCode;
719 }
720
721 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
722
723 //
724 // If we are not a top level request then we just complete the request
725 // with the current status code.
726 //
727
728 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
729
730 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
731 return ExceptionCode;
732 }
733
734 //
735 // Store this error into the Irp for posting back to the Io system.
736 //
737
738 Irp->IoStatus.Status = ExceptionCode;
739
740 if (IoIsErrorUserInduced( ExceptionCode )) {
741
742 //
743 // Check for the various error conditions that can be caused by,
744 // and possibly resolved my the user.
745 //
746
747 if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
748
749 //
750 // Now we are at the top level file system entry point.
751 //
752 // If we have already posted this request then the device to
753 // verify is in the original thread. Find this via the Irp.
754 //
755
756 Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
757 IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
758
759 //
760 // If there is no device in that location then check in the
761 // current thread.
762 //
763
764 if (Device == NULL) {
765
766 Device = IoGetDeviceToVerify( PsGetCurrentThread() );
767 IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
768
769 NT_ASSERT( Device != NULL );
770
771 }
772
773 //
774 // It turns out some storage drivers really do set invalid non-NULL device
775 // objects to verify.
776 //
777 // To work around this, completely ignore the device to verify in the thread,
778 // and just use our real device object instead.
779 //
780
781 if (IrpContext->Vcb) {
782
783 Device = IrpContext->Vcb->Vpb->RealDevice;
784 }
785
786 //
787 // Let's not BugCheck just because the device to verify is somehow still NULL.
788 //
789
790 if (Device == NULL) {
791
792 ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
793
794 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
795
796 return ExceptionCode;
797 }
798
799 //
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.
803 //
804
805 return CdPerformVerify( IrpContext, Irp, Device );
806 }
807
808 //
809 // The other user induced conditions generate an error unless
810 // they have been disabled for this request.
811 //
812
813 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS )) {
814
815 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
816
817 return ExceptionCode;
818
819 }
820 //
821 // Generate a pop-up.
822 //
823 else {
824
825 if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) {
826
827 Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb;
828
829 } else {
830
831 Vpb = NULL;
832 }
833
834
835 //
836 // The device to verify is either in my thread local storage
837 // or that of the thread that owns the Irp.
838 //
839
840 Thread = Irp->Tail.Overlay.Thread;
841 Device = IoGetDeviceToVerify( Thread );
842
843 if (Device == NULL) {
844
845 Thread = PsGetCurrentThread();
846 Device = IoGetDeviceToVerify( Thread );
847
848 NT_ASSERT( Device != NULL );
849 }
850
851 //
852 // It turns out some storage drivers really do set invalid non-NULL device
853 // objects to verify.
854 //
855 // To work around this, completely ignore the device to verify in the thread,
856 // and just use our real device object instead.
857 //
858
859 if (IrpContext->Vcb) {
860
861 Device = IrpContext->Vcb->Vpb->RealDevice;
862 }
863
864 //
865 // Let's not BugCheck just because the device to verify is somehow still NULL.
866 //
867
868 if (Device == NULL) {
869
870 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
871
872 return ExceptionCode;
873 }
874
875 //
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.
880 //
881
882 IoMarkIrpPending( Irp );
883 IoRaiseHardError( Irp, Vpb, Device );
884
885 //
886 // We will be handing control back to the caller here, so
887 // reset the saved device object.
888 //
889
890 IoSetDeviceToVerify( Thread, NULL );
891
892 //
893 // The Irp will be completed by Io or resubmitted. In either
894 // case we must clean up the IrpContext here.
895 //
896
897 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
898 return STATUS_PENDING;
899 }
900 }
901
902 //
903 // This is just a run of the mill error.
904 //
905
906 CdCompleteRequest( IrpContext, Irp, ExceptionCode );
907
908 return ExceptionCode;
909 }
910
911 \f
912 VOID
913 CdCompleteRequest (
914 _Inout_opt_ PIRP_CONTEXT IrpContext,
915 _Inout_opt_ PIRP Irp,
916 _In_ NTSTATUS Status
917 )
918
919 /*++
920
921 Routine Description:
922
923 This routine completes a Irp and cleans up the IrpContext. Either or
924 both of these may not be specified.
925
926 Arguments:
927
928 Irp - Supplies the Irp being processed.
929
930 Status - Supplies the status to complete the Irp with
931
932 Return Value:
933
934 None.
935
936 --*/
937
938 {
939 ASSERT_OPTIONAL_IRP_CONTEXT( IrpContext );
940 ASSERT_OPTIONAL_IRP( Irp );
941
942 //
943 // Cleanup the IrpContext if passed in here.
944 //
945
946 if (ARGUMENT_PRESENT( IrpContext )) {
947
948 CdCleanupIrpContext( IrpContext, FALSE );
949 }
950
951 //
952 // If we have an Irp then complete the irp.
953 //
954
955 if (ARGUMENT_PRESENT( Irp )) {
956
957 //
958 // Clear the information field in case we have used this Irp
959 // internally.
960 //
961
962 if (NT_ERROR( Status ) &&
963 FlagOn( Irp->Flags, IRP_INPUT_OPERATION )) {
964
965 Irp->IoStatus.Information = 0;
966 }
967
968 Irp->IoStatus.Status = Status;
969
970 AssertVerifyDeviceIrp( Irp );
971
972 IoCompleteRequest( Irp, IO_CD_ROM_INCREMENT );
973 }
974
975 return;
976 }
977
978 \f
979 VOID
980 CdSetThreadContext (
981 _Inout_ PIRP_CONTEXT IrpContext,
982 _In_ PTHREAD_CONTEXT ThreadContext
983 )
984
985 /*++
986
987 Routine Description:
988
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.
994
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.
997
998 Arguments:
999
1000 ThreadContext - Address on stack for local storage if not already present.
1001
1002 ForceTopLevel - We force this request to appear top level regardless of
1003 any previous stack value.
1004
1005 Return Value:
1006
1007 None
1008
1009 --*/
1010
1011 {
1012 PTHREAD_CONTEXT CurrentThreadContext;
1013 #ifdef __REACTOS__
1014 ULONG_PTR StackTop;
1015 ULONG_PTR StackBottom;
1016 #endif
1017
1018 PAGED_CODE();
1019
1020 ASSERT_IRP_CONTEXT( IrpContext );
1021
1022 //
1023 // Get the current top-level irp out of the thread storage.
1024 // If NULL then this is the top-level request.
1025 //
1026
1027 CurrentThreadContext = (PTHREAD_CONTEXT) IoGetTopLevelIrp();
1028
1029 if (CurrentThreadContext == NULL) {
1030
1031 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL );
1032 }
1033
1034 //
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.
1038 //
1039 // The following must be true for the current to be a valid Cdfs context.
1040 //
1041 // Structure must lie within current stack.
1042 // Address must be ULONG aligned.
1043 // Cdfs signature must be present.
1044 //
1045 // If this is not a valid Cdfs context then use the input thread
1046 // context and store it in the top level context.
1047 //
1048
1049 #ifdef __REACTOS__
1050 IoGetStackLimits( &StackTop, &StackBottom);
1051 #endif
1052
1053 #ifdef _MSC_VER
1054 #pragma warning(suppress: 6011) // Bug in PREFast around bitflag operations
1055 #endif
1056 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL ) ||
1057 #ifndef __REACTOS__
1058 (!IoWithinStackLimits( (ULONG_PTR)CurrentThreadContext, sizeof( THREAD_CONTEXT ) ) ||
1059 #else
1060 (((ULONG_PTR) CurrentThreadContext > StackBottom - sizeof( THREAD_CONTEXT )) ||
1061 ((ULONG_PTR) CurrentThreadContext <= StackTop) ||
1062 #endif
1063 FlagOn( (ULONG_PTR) CurrentThreadContext, 0x3 ) ||
1064 (CurrentThreadContext->Cdfs != 0x53464443))) {
1065
1066 ThreadContext->Cdfs = 0x53464443;
1067 ThreadContext->SavedTopLevelIrp = (PIRP) CurrentThreadContext;
1068 ThreadContext->TopLevelIrpContext = IrpContext;
1069 IoSetTopLevelIrp( (PIRP) ThreadContext );
1070
1071 IrpContext->TopLevel = IrpContext;
1072 IrpContext->ThreadContext = ThreadContext;
1073
1074 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS );
1075
1076 //
1077 // Otherwise use the IrpContext in the thread context.
1078 //
1079
1080 } else {
1081
1082 IrpContext->TopLevel = CurrentThreadContext->TopLevelIrpContext;
1083 }
1084
1085 return;
1086 }
1087
1088
1089 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE)
1090 _IRQL_requires_same_
1091 _Success_(return != FALSE)
1092 BOOLEAN
1093 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1094 CdFastIoCheckIfPossible (
1095 _In_ PFILE_OBJECT FileObject,
1096 _In_ PLARGE_INTEGER FileOffset,
1097 _In_ ULONG Length,
1098 _In_ BOOLEAN Wait,
1099 _In_ ULONG LockKey,
1100 _In_ BOOLEAN CheckForReadOperation,
1101 _Pre_notnull_
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
1106 )
1107
1108 /*++
1109
1110 Routine Description:
1111
1112 This routine checks if fast i/o is possible for a read/write operation
1113
1114 Arguments:
1115
1116 FileObject - Supplies the file object used in the query
1117
1118 FileOffset - Supplies the starting byte offset for the read/write operation
1119
1120 Length - Supplies the length, in bytes, of the read/write operation
1121
1122 Wait - Indicates if we can wait
1123
1124 LockKey - Supplies the lock key
1125
1126 CheckForReadOperation - Indicates if this is a check for a read or write
1127 operation
1128
1129 IoStatus - Receives the status of the operation if our return value is
1130 FastIoReturnError
1131
1132 Return Value:
1133
1134 BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs
1135 to take the long route.
1136
1137 --*/
1138
1139 {
1140 PFCB Fcb;
1141 TYPE_OF_OPEN TypeOfOpen;
1142 LARGE_INTEGER LargeLength;
1143
1144 PAGED_CODE();
1145
1146 UNREFERENCED_PARAMETER( Wait );
1147 UNREFERENCED_PARAMETER( DeviceObject );
1148
1149 //
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.
1152 //
1153
1154 TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
1155
1156 if ((TypeOfOpen != UserFileOpen) || !CheckForReadOperation) {
1157
1158 IoStatus->Status = STATUS_INVALID_PARAMETER;
1159 return TRUE;
1160 }
1161
1162 LargeLength.QuadPart = Length;
1163
1164 //
1165 // Check whether the file locks will allow for fast io.
1166 //
1167
1168 if ((Fcb->FileLock == NULL) ||
1169 FsRtlFastCheckLockForRead( Fcb->FileLock,
1170 FileOffset,
1171 &LargeLength,
1172 LockKey,
1173 FileObject,
1174 PsGetCurrentProcess() )) {
1175
1176 return TRUE;
1177 }
1178
1179 return FALSE;
1180 }
1181
1182 \f
1183 ULONG
1184 CdSerial32 (
1185 _In_reads_bytes_(ByteCount) PCHAR Buffer,
1186 _In_ ULONG ByteCount
1187 )
1188 /*++
1189
1190 Routine Description:
1191
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.
1195
1196 Arguments:
1197
1198 Buffer - Pointer to the buffer to generate the ID for.
1199
1200 ByteCount - Number of bytes in the buffer.
1201
1202 Return Value:
1203
1204 ULONG - The 32 bit serial number.
1205
1206 --*/
1207
1208 {
1209 union {
1210 UCHAR Bytes[4];
1211 ULONG SerialId;
1212 } Checksum;
1213
1214 PAGED_CODE();
1215
1216 //
1217 // Initialize the serial number.
1218 //
1219
1220 Checksum.SerialId = 0;
1221
1222 //
1223 // Continue while there are more bytes to use.
1224 //
1225
1226 while (ByteCount--) {
1227
1228 //
1229 // Increment this sub-checksum.
1230 //
1231
1232 Checksum.Bytes[ByteCount & 0x3] += *(Buffer++);
1233 }
1234
1235 //
1236 // Return the checksums as a ULONG.
1237 //
1238
1239 return Checksum.SerialId;
1240 }
1241
1242