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