[CDFS_NEW] Replace old driver with a Ms-PL licensed version straight out of the drive...
[reactos.git] / drivers / filesystems / cdfs_new / deviosup.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 DevIoSup.c
8
9 Abstract:
10
11 This module implements the low lever disk read/write support for Cdfs.
12
13
14 --*/
15
16 #include "CdProcs.h"
17
18 //
19 // The Bug check file id for this module
20 //
21
22 #define BugCheckFileId (CDFS_BUG_CHECK_DEVIOSUP)
23
24 //
25 // Local structure definitions
26 //
27
28 //
29 // An array of these structures is passed to CdMultipleAsync describing
30 // a set of runs to execute in parallel.
31 //
32
33 typedef struct _IO_RUN {
34
35 //
36 // Disk offset to read from and number of bytes to read. These
37 // must be a multiple of 2048 and the disk offset is also a
38 // multiple of 2048.
39 //
40
41 LONGLONG DiskOffset;
42 ULONG DiskByteCount;
43
44 //
45 // Current position in user buffer. This is the final destination for
46 // this portion of the Io transfer.
47 //
48
49 PVOID UserBuffer;
50
51 //
52 // Buffer to perform the transfer to. If this is the same as the
53 // user buffer above then we are using the user's buffer. Otherwise
54 // we either allocated a temporary buffer or are using a different portion
55 // of the user's buffer.
56 //
57 // TransferBuffer - Read full sectors into this location. This can
58 // be a pointer into the user's buffer at the exact location the
59 // data should go. It can also be an earlier point in the user's
60 // buffer if the complete I/O doesn't start on a sector boundary.
61 // It may also be a pointer into an allocated buffer.
62 //
63 // TransferByteCount - Count of bytes to transfer to user's buffer. A
64 // value of zero indicates that we did do the transfer into the
65 // user's buffer directly.
66 //
67 // TransferBufferOffset - Offset in this buffer to begin the transfer
68 // to the user's buffer.
69 //
70
71 PVOID TransferBuffer;
72 ULONG TransferByteCount;
73 ULONG TransferBufferOffset;
74
75 //
76 // This is the Mdl describing the locked pages in memory. It may
77 // be allocated to describe the allocated buffer. Or it may be
78 // the Mdl in the originating Irp. The MdlOffset is the offset of
79 // the current buffer from the beginning of the buffer described by
80 // the Mdl below. If the TransferMdl is not the same as the Mdl
81 // in the user's Irp then we know we have allocated it.
82 //
83
84 PMDL TransferMdl;
85 PVOID TransferVirtualAddress;
86
87 //
88 // Associated Irp used to perform the Io.
89 //
90
91 PIRP SavedIrp;
92
93 } IO_RUN;
94 typedef IO_RUN *PIO_RUN;
95
96 #define MAX_PARALLEL_IOS 5
97
98 //
99 // Local support routines
100 //
101
102 _Requires_lock_held_(_Global_critical_region_)
103 BOOLEAN
104 CdPrepareBuffers (
105 _In_ PIRP_CONTEXT IrpContext,
106 _In_ PIRP Irp,
107 _In_ PFCB Fcb,
108 _In_reads_bytes_(ByteCount) PVOID UserBuffer,
109 _In_ ULONG UserBufferOffset,
110 _In_ LONGLONG StartingOffset,
111 _In_ ULONG ByteCount,
112 _Out_ PIO_RUN IoRuns,
113 _Out_ PULONG RunCount,
114 _Out_ PULONG ThisByteCount
115 );
116
117 _Requires_lock_held_(_Global_critical_region_)
118 VOID
119 CdPrepareXABuffers (
120 _In_ PIRP_CONTEXT IrpContext,
121 _In_ PIRP Irp,
122 _In_ PFCB Fcb,
123 _In_reads_bytes_(ByteCount) PVOID UserBuffer,
124 _In_ ULONG UserBufferOffset,
125 _In_ LONGLONG StartingOffset,
126 _In_ ULONG ByteCount,
127 _Out_ PIO_RUN IoRuns,
128 _Out_ PULONG RunCount,
129 _Out_ PULONG ThisByteCount
130 );
131
132 BOOLEAN
133 CdFinishBuffers (
134 _In_ PIRP_CONTEXT IrpContext,
135 _Inout_ PIO_RUN IoRuns,
136 _In_ ULONG RunCount,
137 _In_ BOOLEAN FinalCleanup,
138 _In_ BOOLEAN SaveXABuffer
139 );
140
141 _Requires_lock_held_(_Global_critical_region_)
142 VOID
143 CdMultipleAsync (
144 _In_ PIRP_CONTEXT IrpContext,
145 _In_ PFCB Fcb,
146 _In_ ULONG RunCount,
147 _Inout_ PIO_RUN IoRuns
148 );
149
150 VOID
151 CdMultipleXAAsync (
152 _In_ PIRP_CONTEXT IrpContext,
153 _In_ ULONG RunCount,
154 _Inout_ PIO_RUN IoRuns,
155 _In_ PRAW_READ_INFO RawReads,
156 _In_ TRACK_MODE_TYPE TrackMode
157 );
158
159 _Requires_lock_held_(_Global_critical_region_)
160 VOID
161 CdSingleAsync (
162 _In_ PIRP_CONTEXT IrpContext,
163 _In_ PIO_RUN Run,
164 _In_ PFCB Fcb
165 );
166
167 VOID
168 CdWaitSync (
169 _In_ PIRP_CONTEXT IrpContext
170 );
171
172 // Tell prefast this is a completion routine.
173 IO_COMPLETION_ROUTINE CdMultiSyncCompletionRoutine;
174
175 // Tell prefast this is a completion routine
176 IO_COMPLETION_ROUTINE CdMultiAsyncCompletionRoutine;
177
178 // Tell prefast this is a completion routine
179 IO_COMPLETION_ROUTINE CdSingleSyncCompletionRoutine;
180
181 // Tell prefast this is a completion routine
182 IO_COMPLETION_ROUTINE CdSingleAsyncCompletionRoutine;
183
184 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT))))
185 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE)))
186 VOID
187 CdReadAudioSystemFile (
188 _In_ PIRP_CONTEXT IrpContext,
189 _In_ PFCB Fcb,
190 _In_ LONGLONG StartingOffset,
191 _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount,
192 _Out_writes_bytes_(ByteCount) PVOID SystemBuffer
193 );
194
195 _Requires_lock_held_(_Global_critical_region_)
196 BOOLEAN
197 CdReadDirDataThroughCache (
198 _In_ PIRP_CONTEXT IrpContext,
199 _In_ PIO_RUN Run
200 );
201
202 #ifdef ALLOC_PRAGMA
203 #pragma alloc_text(PAGE, CdCreateUserMdl)
204 #pragma alloc_text(PAGE, CdMultipleAsync)
205 #pragma alloc_text(PAGE, CdMultipleXAAsync)
206 #pragma alloc_text(PAGE, CdNonCachedRead)
207 #pragma alloc_text(PAGE, CdNonCachedXARead)
208 #pragma alloc_text(PAGE, CdVolumeDasdWrite)
209 #pragma alloc_text(PAGE, CdFinishBuffers)
210 #pragma alloc_text(PAGE, CdPerformDevIoCtrl)
211 #pragma alloc_text(PAGE, CdPerformDevIoCtrlEx)
212 #pragma alloc_text(PAGE, CdPrepareBuffers)
213 #pragma alloc_text(PAGE, CdPrepareXABuffers)
214 #pragma alloc_text(PAGE, CdReadAudioSystemFile)
215 #pragma alloc_text(PAGE, CdReadSectors)
216 #pragma alloc_text(PAGE, CdSingleAsync)
217 #pragma alloc_text(PAGE, CdWaitSync)
218 #pragma alloc_text(PAGE, CdReadDirDataThroughCache)
219 #pragma alloc_text(PAGE, CdFreeDirCache)
220 #pragma alloc_text(PAGE, CdLbnToMmSsFf)
221 #pragma alloc_text(PAGE, CdHijackIrpAndFlushDevice)
222 #endif
223
224
225 VOID
226 CdLbnToMmSsFf (
227 _In_ ULONG Blocks,
228 _Out_writes_(3) PUCHAR Msf
229 )
230
231 /*++
232
233 Routine Description:
234
235 Convert Lbn to MSF format.
236
237 Arguments:
238
239 Msf - on output, set to 0xMmSsFf representation of blocks.
240
241 --*/
242
243 {
244 PAGED_CODE();
245
246 Blocks += 150; // Lbn 0 == 00:02:00, 1sec == 75 frames.
247
248 Msf[0] = (UCHAR)(Blocks % 75); // Frames
249 Blocks /= 75; // -> Seconds
250 Msf[1] = (UCHAR)(Blocks % 60); // Seconds
251 Blocks /= 60; // -> Minutes
252 Msf[2] = (UCHAR)Blocks; // Minutes
253 }
254
255
256 __inline
257 TRACK_MODE_TYPE
258 CdFileTrackMode (
259 _In_ PFCB Fcb
260 )
261
262 /*++
263
264 Routine Description:
265
266 This routine converts FCB XA file type flags to the track mode
267 used by the device drivers.
268
269 Arguments:
270
271 Fcb - Fcb representing the file to read.
272
273 Return Value:
274
275 TrackMode of the file represented by the Fcb.
276
277 --*/
278 {
279 NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE |
280 FCB_STATE_MODE2_FILE |
281 FCB_STATE_DA_FILE ));
282
283 if (FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
284
285 return XAForm2;
286
287 } else if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
288
289 return CDDA;
290
291 }
292
293 //
294 // FCB_STATE_MODE2_FILE
295 //
296
297 return YellowMode2;
298 }
299
300 \f
301 _Requires_lock_held_(_Global_critical_region_)
302 NTSTATUS
303 CdNonCachedRead (
304 _In_ PIRP_CONTEXT IrpContext,
305 _In_ PFCB Fcb,
306 _In_ LONGLONG StartingOffset,
307 _In_ ULONG ByteCount
308 )
309
310 /*++
311
312 Routine Description:
313
314 This routine performs the non-cached reads to 'cooked' sectors (2048 bytes
315 per sector). This is done by performing the following in a loop.
316
317 Fill in the IoRuns array for the next block of Io.
318 Send the Io to the device.
319 Perform any cleanup on the Io runs array.
320
321 We will not do async Io to any request that generates non-aligned Io.
322 Also we will not perform async Io if it will exceed the size of our
323 IoRuns array. These should be the unusual cases but we will raise
324 or return CANT_WAIT in this routine if we detect this case.
325
326 Arguments:
327
328 Fcb - Fcb representing the file to read.
329
330 StartingOffset - Logical offset in the file to read from.
331
332 ByteCount - Number of bytes to read.
333
334 Return Value:
335
336 NTSTATUS - Status indicating the result of the operation.
337
338 --*/
339
340 {
341 NTSTATUS Status = STATUS_SUCCESS;
342
343 IO_RUN IoRuns[MAX_PARALLEL_IOS];
344 ULONG RunCount = 0;
345 ULONG CleanupRunCount = 0;
346
347 PVOID UserBuffer;
348 ULONG UserBufferOffset = 0;
349 LONGLONG CurrentOffset = StartingOffset;
350 ULONG RemainingByteCount = ByteCount;
351 ULONG ThisByteCount;
352
353 BOOLEAN Unaligned;
354 BOOLEAN FlushIoBuffers = FALSE;
355 BOOLEAN FirstPass = TRUE;
356
357 PAGED_CODE();
358
359 //
360 // We want to make sure the user's buffer is locked in all cases.
361 //
362
363 if (IrpContext->Irp->MdlAddress == NULL) {
364
365 CdCreateUserMdl( IrpContext, ByteCount, TRUE, IoWriteAccess );
366 }
367
368 CdMapUserBuffer( IrpContext, &UserBuffer);
369
370 //
371 // Special case the root directory and path table for a music volume.
372 //
373
374 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK ) &&
375 ((SafeNodeType( Fcb ) == CDFS_NTC_FCB_INDEX) ||
376 (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE))) {
377
378 CdReadAudioSystemFile( IrpContext,
379 Fcb,
380 StartingOffset,
381 ByteCount,
382 UserBuffer );
383
384 return STATUS_SUCCESS;
385 }
386
387 //
388 // If we're going to use the sector cache for this request, then
389 // mark the request waitable.
390 //
391
392 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
393 (NULL != Fcb->Vcb->SectorCacheBuffer) &&
394 (VcbMounted == IrpContext->Vcb->VcbCondition)) {
395
396 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
397
398 KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
399 NotificationEvent,
400 FALSE );
401
402 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
403 }
404 }
405
406 //
407 // Use a try-finally to perform the final cleanup.
408 //
409
410 try {
411
412 //
413 // Loop while there are more bytes to transfer.
414 //
415
416 do {
417
418 //
419 // Call prepare buffers to set up the next entries
420 // in the IoRuns array. Remember if there are any
421 // unaligned entries. This routine will raise CANT_WAIT
422 // if there are unaligned entries for an async request.
423 //
424
425 RtlZeroMemory( IoRuns, sizeof( IoRuns ));
426
427 Unaligned = CdPrepareBuffers( IrpContext,
428 IrpContext->Irp,
429 Fcb,
430 UserBuffer,
431 UserBufferOffset,
432 CurrentOffset,
433 RemainingByteCount,
434 IoRuns,
435 &CleanupRunCount,
436 &ThisByteCount );
437
438
439 RunCount = CleanupRunCount;
440
441 //
442 // If this is an async request and there aren't enough entries
443 // in the Io array then post the request.
444 //
445
446 if ((ThisByteCount < RemainingByteCount) &&
447 !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
448
449 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
450 }
451
452 //
453 // If the entire Io is contained in a single run then
454 // we can pass the Io down to the driver. Send the driver down
455 // and wait on the result if this is synchronous.
456 //
457
458 if ((RunCount == 1) && !Unaligned && FirstPass) {
459
460 CdSingleAsync( IrpContext,&IoRuns[0], Fcb );
461
462 //
463 // No cleanup needed for the IoRuns array here.
464 //
465
466 CleanupRunCount = 0;
467
468 //
469 // Wait if we are synchronous, otherwise return
470 //
471
472 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
473
474 CdWaitSync( IrpContext );
475
476 Status = IrpContext->Irp->IoStatus.Status;
477
478 //
479 // Our completion routine will free the Io context but
480 // we do want to return STATUS_PENDING.
481 //
482
483 } else {
484
485 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
486 Status = STATUS_PENDING;
487 }
488
489 try_return( NOTHING );
490 }
491
492 //
493 // Otherwise we will perform multiple Io to read in the data.
494 //
495
496 CdMultipleAsync( IrpContext, Fcb, RunCount, IoRuns );
497
498 //
499 // If this is a synchronous request then perform any necessary
500 // post-processing.
501 //
502
503 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
504
505 //
506 // Wait for the request to complete.
507 //
508
509 CdWaitSync( IrpContext );
510
511 Status = IrpContext->Irp->IoStatus.Status;
512
513 //
514 // Exit this loop if there is an error.
515 //
516
517 if (!NT_SUCCESS( Status )) {
518
519 try_return( NOTHING );
520 }
521
522 //
523 // Perform post read operations on the IoRuns if
524 // necessary.
525 //
526
527 if (Unaligned &&
528 CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, FALSE )) {
529
530 FlushIoBuffers = TRUE;
531 }
532
533 CleanupRunCount = 0;
534
535 //
536 // Exit this loop if there are no more bytes to transfer
537 // or we have any error.
538 //
539
540 RemainingByteCount -= ThisByteCount;
541 CurrentOffset += ThisByteCount;
542 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
543 UserBufferOffset += ThisByteCount;
544
545 //
546 // Otherwise this is an asynchronous request. Always return
547 // STATUS_PENDING.
548 //
549
550 } else {
551
552 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
553 CleanupRunCount = 0;
554 try_return( Status = STATUS_PENDING );
555 break;
556 }
557
558 FirstPass = FALSE;
559 } while (RemainingByteCount != 0);
560
561 //
562 // Flush the hardware cache if we performed any copy operations.
563 //
564
565 if (FlushIoBuffers) {
566
567 KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
568 }
569
570 try_exit: NOTHING;
571 } finally {
572
573 //
574 // Perform final cleanup on the IoRuns if necessary.
575 //
576
577 if (CleanupRunCount != 0) {
578
579 CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
580 }
581 }
582
583 return Status;
584 }
585
586 \f
587
588 _Requires_lock_held_(_Global_critical_region_)
589 NTSTATUS
590 CdNonCachedXARead (
591 _In_ PIRP_CONTEXT IrpContext,
592 _In_ PFCB Fcb,
593 _In_ LONGLONG StartingOffset,
594 _In_ ULONG ByteCount
595 )
596
597 /*++
598
599 Routine Description:
600
601 This routine performs the non-cached reads for 'raw' sectors (2352 bytes
602 per sector). We also prepend a hard-coded RIFF header of 44 bytes to the file.
603 All of this is already reflected in the file size.
604
605 We start by checking whether to prepend any portion of the RIFF header. Then we check
606 if the last raw sector read was from the beginning portion of this file, deallocating
607 that buffer if necessary. Finally we do the following in a loop.
608
609 Fill the IoRuns array for the next block of Io.
610 Send the Io to the device driver.
611 Perform any cleanup necessary on the IoRuns array.
612
613 We will not do any async request in this path. The request would have been
614 posted to a worker thread before getting to this point.
615
616 Arguments:
617
618 Fcb - Fcb representing the file to read.
619
620 StartingOffset - Logical offset in the file to read from.
621
622 ByteCount - Number of bytes to read.
623
624 Return Value:
625
626 NTSTATUS - Status indicating the result of the operation.
627
628 --*/
629
630 {
631 NTSTATUS Status = STATUS_SUCCESS;
632
633 RIFF_HEADER LocalRiffHeader;
634 PRIFF_HEADER RiffHeader;
635
636 RAW_READ_INFO RawReads[MAX_PARALLEL_IOS];
637 IO_RUN IoRuns[MAX_PARALLEL_IOS];
638 ULONG RunCount = 0;
639 ULONG CleanupRunCount = 0;
640
641 PVOID UserBuffer;
642 ULONG UserBufferOffset = 0;
643 LONGLONG CurrentOffset = StartingOffset;
644 ULONG RemainingByteCount = ByteCount;
645 ULONG ThisByteCount = 0;
646 ULONG Address = 0;
647
648 BOOLEAN TryingYellowbookMode2 = FALSE;
649
650 TRACK_MODE_TYPE TrackMode;
651
652 PAGED_CODE();
653
654 //
655 // We want to make sure the user's buffer is locked in all cases.
656 //
657
658 if (IrpContext->Irp->MdlAddress == NULL) {
659
660 CdCreateUserMdl( IrpContext, ByteCount, TRUE, IoWriteAccess );
661 }
662
663 //
664 // The byte count was rounded up to a logical sector boundary. It has
665 // nothing to do with the raw sectors on disk. Limit the remaining
666 // byte count to file size.
667 //
668
669 if (CurrentOffset + RemainingByteCount > Fcb->FileSize.QuadPart) {
670
671 RemainingByteCount = (ULONG) (Fcb->FileSize.QuadPart - CurrentOffset);
672 }
673
674 CdMapUserBuffer( IrpContext, &UserBuffer);
675
676 //
677 // Use a try-finally to perform the final cleanup.
678 //
679
680 try {
681
682 //
683 // If the initial offset lies within the RIFF header then copy the
684 // necessary bytes to the user's buffer.
685 //
686
687 if (CurrentOffset < sizeof( RIFF_HEADER )) {
688
689 //
690 // Copy the appropriate RIFF header.
691 //
692
693 if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
694
695 //
696 // Create the pseudo entries for a music disk.
697 //
698
699 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
700
701 PAUDIO_PLAY_HEADER AudioPlayHeader;
702 PTRACK_DATA TrackData;
703
704 AudioPlayHeader = (PAUDIO_PLAY_HEADER) &LocalRiffHeader;
705 TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber];
706
707 //
708 // Copy the data header into our local buffer.
709 //
710
711 RtlCopyMemory( AudioPlayHeader,
712 CdAudioPlayHeader,
713 sizeof( AUDIO_PLAY_HEADER ));
714
715 //
716 // Copy the serial number into the Id field. Also
717 // the track number in the TOC.
718 //
719
720 AudioPlayHeader->DiskID = Fcb->Vcb->Vpb->SerialNumber;
721 AudioPlayHeader->TrackNumber = TrackData->TrackNumber;
722
723 //
724 // One frame == One sector.
725 // One second == 75 frames (winds up being a 44.1khz sample)
726 //
727 // Note: LBN 0 == 0:2:0 (MSF)
728 //
729
730 //
731 // Fill in the address (both MSF and Lbn format) and length fields.
732 //
733
734 SwapCopyUchar4( &Address, TrackData->Address);
735 CdLbnToMmSsFf( Address, AudioPlayHeader->TrackAddress);
736
737 SwapCopyUchar4( &AudioPlayHeader->StartingSector, TrackData->Address);
738
739 //
740 // Go to the next track and find the starting point.
741 //
742
743 TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber + 1];
744
745 SwapCopyUchar4( &AudioPlayHeader->SectorCount, TrackData->Address);
746
747 //
748 // Now compute the difference. If there is an error then use
749 // a length of zero.
750 //
751
752 if (AudioPlayHeader->SectorCount < AudioPlayHeader->StartingSector) {
753
754 AudioPlayHeader->SectorCount = 0;
755
756 } else {
757
758 AudioPlayHeader->SectorCount -= AudioPlayHeader->StartingSector;
759 }
760
761 //
762 // Use the sector count to determine the MSF length. Bias by 150 to make
763 // it an "lbn" since the conversion routine corrects for Lbn 0 == 0:2:0;
764 //
765
766 Address = AudioPlayHeader->SectorCount - 150;
767 CdLbnToMmSsFf( Address, AudioPlayHeader->TrackLength);
768
769 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
770
771 RtlCopyMemory( UserBuffer,
772 Add2Ptr( AudioPlayHeader,
773 sizeof( RIFF_HEADER ) - ThisByteCount,
774 PCHAR ),
775 ThisByteCount );
776
777 //
778 // CD-XA CDDA
779 //
780
781 } else {
782
783 //
784 // The WAVE header format is actually much closer to an audio play
785 // header in format but we only need to modify the filesize fields.
786 //
787
788 RiffHeader = &LocalRiffHeader;
789
790 //
791 // Copy the data header into our local buffer and add the file size to it.
792 //
793
794 RtlCopyMemory( RiffHeader,
795 CdXAAudioPhileHeader,
796 sizeof( RIFF_HEADER ));
797
798 RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
799 RiffHeader->RawSectors += Fcb->FileSize.LowPart;
800
801 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
802 RtlCopyMemory( UserBuffer,
803 Add2Ptr( RiffHeader,
804 sizeof( RIFF_HEADER ) - ThisByteCount,
805 PCHAR ),
806 ThisByteCount );
807 }
808
809 //
810 // CD-XA non-audio
811 //
812
813 } else {
814
815 NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE ));
816
817 RiffHeader = &LocalRiffHeader;
818
819 //
820 // Copy the data header into our local buffer and add the file size to it.
821 //
822
823 RtlCopyMemory( RiffHeader,
824 CdXAFileHeader,
825 sizeof( RIFF_HEADER ));
826
827 RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
828 RiffHeader->RawSectors += Fcb->FileSize.LowPart;
829
830 RiffHeader->Attributes = (USHORT) Fcb->XAAttributes;
831 RiffHeader->FileNumber = (UCHAR) Fcb->XAFileNumber;
832
833 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
834 RtlCopyMemory( UserBuffer,
835 Add2Ptr( RiffHeader,
836 sizeof( RIFF_HEADER ) - ThisByteCount,
837 PCHAR ),
838 ThisByteCount );
839 }
840
841 //
842 // Adjust the starting offset and byte count to reflect that
843 // we copied over the RIFF bytes.
844 //
845
846 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
847 UserBufferOffset += ThisByteCount;
848 CurrentOffset += ThisByteCount;
849 RemainingByteCount -= ThisByteCount;
850 }
851
852 //
853 // Set up the appropriate trackmode
854 //
855
856 TrackMode = CdFileTrackMode(Fcb);
857
858 //
859 // Loop while there are more bytes to transfer.
860 //
861
862 while (RemainingByteCount != 0) {
863
864 //
865 // Call prepare buffers to set up the next entries
866 // in the IoRuns array. Remember if there are any
867 // unaligned entries. If we're just retrying the previous
868 // runs with a different track mode, then don't do anything here.
869 //
870
871 if (!TryingYellowbookMode2) {
872
873 RtlZeroMemory( IoRuns, sizeof( IoRuns ));
874 RtlZeroMemory( RawReads, sizeof( RawReads ));
875
876 CdPrepareXABuffers( IrpContext,
877 IrpContext->Irp,
878 Fcb,
879 UserBuffer,
880 UserBufferOffset,
881 CurrentOffset,
882 RemainingByteCount,
883 IoRuns,
884 &CleanupRunCount,
885 &ThisByteCount );
886 }
887
888 //
889 // Perform multiple Io to read in the data. Note that
890 // there may be no Io to do if we were able to use an
891 // existing buffer from the Vcb.
892 //
893
894 if (CleanupRunCount != 0) {
895
896 RunCount = CleanupRunCount;
897
898 CdMultipleXAAsync( IrpContext,
899 RunCount,
900 IoRuns,
901 RawReads,
902 TrackMode );
903 //
904 // Wait for the request to complete.
905 //
906
907 CdWaitSync( IrpContext );
908
909 Status = IrpContext->Irp->IoStatus.Status;
910
911 //
912 // Exit this loop if there is an error.
913 //
914
915 if (!NT_SUCCESS( Status )) {
916
917 if (!TryingYellowbookMode2 &&
918 FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
919
920 //
921 // There are wacky cases where someone has mastered as CD-XA
922 // but the sectors they claim are Mode2Form2 are really, according
923 // to ATAPI devices, Yellowbook Mode2. We will try once more
924 // with these. Kodak PHOTO-CD has been observed to do this.
925 //
926
927 TryingYellowbookMode2 = TRUE;
928 TrackMode = YellowMode2;
929
930 //
931 // Clear our 'cumulative' error status value
932 //
933
934 IrpContext->IoContext->Status = STATUS_SUCCESS;
935
936 continue;
937 }
938
939 try_return( NOTHING );
940 }
941
942 CleanupRunCount = 0;
943
944 if (TryingYellowbookMode2) {
945
946 //
947 // We succesfully got data when we tried switching the trackmode,
948 // so change the state of the FCB to remember that.
949 //
950
951 SetFlag( Fcb->FcbState, FCB_STATE_MODE2_FILE );
952 ClearFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
953
954 TryingYellowbookMode2 = FALSE;
955 }
956
957 //
958 // Perform post read operations on the IoRuns if
959 // necessary.
960 //
961
962 CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, TRUE );
963 }
964
965 //
966 // Adjust our loop variants.
967 //
968
969 RemainingByteCount -= ThisByteCount;
970 CurrentOffset += ThisByteCount;
971 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
972 UserBufferOffset += ThisByteCount;
973 }
974
975 //
976 // Always flush the hardware cache.
977 //
978
979 KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
980
981 try_exit: NOTHING;
982 } finally {
983
984 //
985 // Perform final cleanup on the IoRuns if necessary.
986 //
987
988 if (CleanupRunCount != 0) {
989
990 CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
991 }
992 }
993
994 return Status;
995 }
996
997 _Requires_lock_held_(_Global_critical_region_)
998 NTSTATUS
999 CdVolumeDasdWrite (
1000 _In_ PIRP_CONTEXT IrpContext,
1001 _In_ PFCB Fcb,
1002 _In_ LONGLONG StartingOffset,
1003 _In_ ULONG ByteCount
1004 )
1005
1006 /*++
1007
1008 Routine Description:
1009
1010 This routine performs the non-cached writes to 'cooked' sectors (2048 bytes
1011 per sector). This is done by filling the IoRun for the desired request
1012 and send it down to the device.
1013
1014 Arguments:
1015
1016 Fcb - Fcb representing the file to read.
1017
1018 StartingOffset - Logical offset in the file to read from.
1019
1020 ByteCount - Number of bytes to read.
1021
1022 Return Value:
1023
1024 NTSTATUS - Status indicating the result of the operation.
1025
1026 --*/
1027
1028 {
1029 NTSTATUS Status;
1030 IO_RUN IoRun;
1031
1032 PAGED_CODE();
1033
1034 //
1035 // We want to make sure the user's buffer is locked in all cases.
1036 //
1037
1038 CdLockUserBuffer( IrpContext, ByteCount, IoReadAccess );
1039
1040 //
1041 // The entire Io can be contained in a single run, just pass
1042 // the Io down to the driver. Send the driver down
1043 // and wait on the result if this is synchronous.
1044 //
1045
1046 RtlZeroMemory( &IoRun, sizeof( IoRun ) );
1047
1048 IoRun.DiskOffset = StartingOffset;
1049 IoRun.DiskByteCount = ByteCount;
1050
1051 CdSingleAsync( IrpContext, &IoRun, Fcb );
1052
1053 //
1054 // Wait if we are synchronous, otherwise return
1055 //
1056
1057 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
1058
1059 CdWaitSync( IrpContext );
1060
1061 Status = IrpContext->Irp->IoStatus.Status;
1062
1063 //
1064 // Our completion routine will free the Io context but
1065 // we do want to return STATUS_PENDING.
1066 //
1067
1068 } else {
1069
1070 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
1071 Status = STATUS_PENDING;
1072 }
1073
1074 return Status;
1075 }
1076
1077
1078 \f
1079 BOOLEAN
1080 CdReadSectors (
1081 _In_ PIRP_CONTEXT IrpContext,
1082 _In_ LONGLONG StartingOffset,
1083 _In_ ULONG ByteCount,
1084 _In_ BOOLEAN ReturnError,
1085 _Out_writes_bytes_(ByteCount) PVOID Buffer,
1086 _In_ PDEVICE_OBJECT TargetDeviceObject
1087 )
1088
1089 /*++
1090
1091 Routine Description:
1092
1093 This routine is called to transfer sectors from the disk to a
1094 specified buffer. It is used for mount and volume verify operations.
1095
1096 This routine is synchronous, it will not return until the operation
1097 is complete or until the operation fails.
1098
1099 The routine allocates an IRP and then passes this IRP to a lower
1100 level driver. Errors may occur in the allocation of this IRP or
1101 in the operation of the lower driver.
1102
1103 Arguments:
1104
1105 StartingOffset - Logical offset on the disk to start the read. This
1106 must be on a sector boundary, no check is made here.
1107
1108 ByteCount - Number of bytes to read. This is an integral number of
1109 2K sectors, no check is made here to confirm this.
1110
1111 ReturnError - Indicates whether we should return TRUE or FALSE
1112 to indicate an error or raise an error condition. This only applies
1113 to the result of the IO. Any other error may cause a raise.
1114
1115 Buffer - Buffer to transfer the disk data into.
1116
1117 TargetDeviceObject - The device object for the volume to be read.
1118
1119 Return Value:
1120
1121 BOOLEAN - Depending on 'RaiseOnError' flag above. TRUE if operation
1122 succeeded, FALSE otherwise.
1123
1124 --*/
1125
1126 {
1127 NTSTATUS Status;
1128 KEVENT Event;
1129 PIRP Irp;
1130
1131 PAGED_CODE();
1132
1133 //
1134 // Initialize the event.
1135 //
1136
1137 KeInitializeEvent( &Event, NotificationEvent, FALSE );
1138
1139 //
1140 // Attempt to allocate the IRP. If unsuccessful, raise
1141 // STATUS_INSUFFICIENT_RESOURCES.
1142 //
1143
1144 Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
1145 TargetDeviceObject,
1146 Buffer,
1147 ByteCount,
1148 (PLARGE_INTEGER) &StartingOffset,
1149 &Event,
1150 &IrpContext->Irp->IoStatus );
1151
1152 if (Irp == NULL) {
1153
1154 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1155 }
1156
1157 //
1158 // Ignore the change line (verify) for mount and verify requests
1159 //
1160
1161 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
1162
1163 //
1164 // Send the request down to the driver. If an error occurs return
1165 // it to the caller.
1166 //
1167
1168 Status = IoCallDriver( TargetDeviceObject, Irp );
1169
1170 //
1171 // If the status was STATUS_PENDING then wait on the event.
1172 //
1173
1174 if (Status == STATUS_PENDING) {
1175
1176 Status = KeWaitForSingleObject( &Event,
1177 Executive,
1178 KernelMode,
1179 FALSE,
1180 NULL );
1181
1182 //
1183 // On a successful wait pull the status out of the IoStatus block.
1184 //
1185
1186 if (NT_SUCCESS( Status )) {
1187
1188 Status = IrpContext->Irp->IoStatus.Status;
1189 }
1190 }
1191
1192 //
1193 // Check whether we should raise in the error case.
1194 //
1195
1196 if (!NT_SUCCESS( Status )) {
1197
1198 if (!ReturnError) {
1199
1200 CdNormalizeAndRaiseStatus( IrpContext, Status );
1201 }
1202
1203 //
1204 // We don't raise, but return FALSE to indicate an error.
1205 //
1206
1207 return FALSE;
1208
1209 //
1210 // The operation completed successfully.
1211 //
1212
1213 } else {
1214
1215 return TRUE;
1216 }
1217 }
1218
1219 \f
1220 NTSTATUS
1221 CdCreateUserMdl (
1222 _In_ PIRP_CONTEXT IrpContext,
1223 _In_ ULONG BufferLength,
1224 _In_ BOOLEAN RaiseOnError,
1225 _In_ LOCK_OPERATION Operation
1226 )
1227
1228 /*++
1229
1230 Routine Description:
1231
1232 This routine locks the specified buffer for read access (we only write into
1233 the buffer). The file system requires this routine since it does not
1234 ask the I/O system to lock its buffers for direct I/O. This routine
1235 may only be called from the Fsd while still in the user context.
1236
1237 This routine is only called if there is not already an Mdl.
1238
1239 Arguments:
1240
1241 BufferLength - Length of user buffer.
1242
1243 RaiseOnError - Indicates if our caller wants this routine to raise on
1244 an error condition.
1245
1246 Operation - IoWriteAccess or IoReadAccess
1247
1248 Return Value:
1249
1250 NTSTATUS - Status from this routine. Error status only returned if
1251 RaiseOnError is FALSE.
1252
1253 --*/
1254
1255 {
1256 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
1257 PMDL Mdl;
1258
1259 PAGED_CODE();
1260
1261 UNREFERENCED_PARAMETER( Operation );
1262 UNREFERENCED_PARAMETER( IrpContext );
1263
1264 ASSERT_IRP_CONTEXT( IrpContext );
1265 ASSERT_IRP( IrpContext->Irp );
1266 NT_ASSERT( IrpContext->Irp->MdlAddress == NULL );
1267
1268 //
1269 // Allocate the Mdl, and Raise if we fail.
1270 //
1271
1272 Mdl = IoAllocateMdl( IrpContext->Irp->UserBuffer,
1273 BufferLength,
1274 FALSE,
1275 FALSE,
1276 IrpContext->Irp );
1277
1278 if (Mdl != NULL) {
1279
1280 //
1281 // Now probe the buffer described by the Irp. If we get an exception,
1282 // deallocate the Mdl and return the appropriate "expected" status.
1283 //
1284
1285 try {
1286
1287 MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
1288
1289 Status = STATUS_SUCCESS;
1290
1291 #pragma warning(suppress: 6320)
1292 } except(EXCEPTION_EXECUTE_HANDLER) {
1293
1294 Status = GetExceptionCode();
1295
1296 IoFreeMdl( Mdl );
1297 IrpContext->Irp->MdlAddress = NULL;
1298
1299 if (!FsRtlIsNtstatusExpected( Status )) {
1300
1301 Status = STATUS_INVALID_USER_BUFFER;
1302 }
1303 }
1304 }
1305
1306 //
1307 // Check if we are to raise or return
1308 //
1309
1310 if (Status != STATUS_SUCCESS) {
1311
1312 if (RaiseOnError) {
1313
1314 CdRaiseStatus( IrpContext, Status );
1315 }
1316 }
1317
1318 //
1319 // Return the status code.
1320 //
1321
1322 return Status;
1323 }
1324
1325 \f
1326 NTSTATUS
1327 CdPerformDevIoCtrlEx (
1328 _In_ PIRP_CONTEXT IrpContext,
1329 _In_ ULONG IoControlCode,
1330 _In_ PDEVICE_OBJECT Device,
1331 _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
1332 _In_ ULONG InputBufferLength,
1333 _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
1334 _In_ ULONG OutputBufferLength,
1335 _In_ BOOLEAN InternalDeviceIoControl,
1336 _In_ BOOLEAN OverrideVerify,
1337 _Out_opt_ PIO_STATUS_BLOCK Iosb
1338 )
1339
1340 /*++
1341
1342 Routine Description:
1343
1344 This routine is called to perform DevIoCtrl functions internally within
1345 the filesystem. We take the status from the driver and return it to our
1346 caller.
1347
1348 Arguments:
1349
1350 IoControlCode - Code to send to driver.
1351
1352 Device - This is the device to send the request to.
1353
1354 OutPutBuffer - Pointer to output buffer.
1355
1356 OutputBufferLength - Length of output buffer above.
1357
1358 InternalDeviceIoControl - Indicates if this is an internal or external
1359 Io control code.
1360
1361 OverrideVerify - Indicates if we should tell the driver not to return
1362 STATUS_VERIFY_REQUIRED for mount and verify.
1363
1364 Iosb - If specified, we return the results of the operation here.
1365
1366 Return Value:
1367
1368 NTSTATUS - Status returned by next lower driver.
1369
1370 --*/
1371
1372 {
1373 NTSTATUS Status;
1374 PIRP Irp;
1375 KEVENT Event;
1376 IO_STATUS_BLOCK LocalIosb;
1377 PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
1378
1379 PAGED_CODE();
1380
1381 UNREFERENCED_PARAMETER( IrpContext );
1382
1383 //
1384 // Check if the user gave us an Iosb.
1385 //
1386
1387 if (ARGUMENT_PRESENT( Iosb )) {
1388
1389 IosbToUse = Iosb;
1390 }
1391
1392 IosbToUse->Status = 0;
1393 IosbToUse->Information = 0;
1394
1395 KeInitializeEvent( &Event, NotificationEvent, FALSE );
1396
1397 Irp = IoBuildDeviceIoControlRequest( IoControlCode,
1398 Device,
1399 InputBuffer,
1400 InputBufferLength,
1401 OutputBuffer,
1402 OutputBufferLength,
1403 InternalDeviceIoControl,
1404 &Event,
1405 IosbToUse );
1406
1407 if (Irp == NULL) {
1408
1409 return STATUS_INSUFFICIENT_RESOURCES;
1410 }
1411
1412 if (OverrideVerify) {
1413
1414 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
1415 }
1416
1417 Status = IoCallDriver( Device, Irp );
1418
1419 //
1420 // We check for device not ready by first checking Status
1421 // and then if status pending was returned, the Iosb status
1422 // value.
1423 //
1424
1425 if (Status == STATUS_PENDING) {
1426
1427 (VOID) KeWaitForSingleObject( &Event,
1428 Executive,
1429 KernelMode,
1430 FALSE,
1431 (PLARGE_INTEGER)NULL );
1432
1433 Status = IosbToUse->Status;
1434 }
1435
1436 NT_ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
1437
1438 return Status;
1439 }
1440
1441
1442 NTSTATUS
1443 FASTCALL
1444 CdPerformDevIoCtrl (
1445 _In_ PIRP_CONTEXT IrpContext,
1446 _In_ ULONG IoControlCode,
1447 _In_ PDEVICE_OBJECT Device,
1448 _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
1449 _In_ ULONG OutputBufferLength,
1450 _In_ BOOLEAN InternalDeviceIoControl,
1451 _In_ BOOLEAN OverrideVerify,
1452 _Out_opt_ PIO_STATUS_BLOCK Iosb
1453 )
1454 {
1455 PAGED_CODE();
1456
1457 return CdPerformDevIoCtrlEx( IrpContext,
1458 IoControlCode,
1459 Device,
1460 NULL,
1461 0,
1462 OutputBuffer,
1463 OutputBufferLength,
1464 InternalDeviceIoControl,
1465 OverrideVerify,
1466 Iosb);
1467 }
1468
1469
1470 \f
1471 //
1472 // Local support routine
1473 //
1474
1475 _Requires_lock_held_(_Global_critical_region_)
1476 BOOLEAN
1477 CdPrepareBuffers (
1478 _In_ PIRP_CONTEXT IrpContext,
1479 _In_ PIRP Irp,
1480 _In_ PFCB Fcb,
1481 _In_reads_bytes_(ByteCount) PVOID UserBuffer,
1482 _In_ ULONG UserBufferOffset,
1483 _In_ LONGLONG StartingOffset,
1484 _In_ ULONG ByteCount,
1485 _Out_ PIO_RUN IoRuns,
1486 _Out_ PULONG RunCount,
1487 _Out_ PULONG ThisByteCount
1488 )
1489
1490 /*++
1491
1492 Routine Description:
1493
1494 This routine is the worker routine which looks up each run of an IO
1495 request and stores an entry for it in the IoRuns array. If the run
1496 begins on an unaligned disk boundary then we will allocate a buffer
1497 and Mdl for the unaligned portion and put it in the IoRuns entry.
1498
1499 This routine will raise CANT_WAIT if an unaligned transfer is encountered
1500 and this request can't wait.
1501
1502 Arguments:
1503
1504 Irp - Originating Irp for this request.
1505
1506 Fcb - This is the Fcb for this data stream. It may be a file, directory,
1507 path table or the volume file.
1508
1509 UserBuffer - Current position in the user's buffer.
1510
1511 UserBufferOffset - Offset from the start of the original user buffer.
1512
1513 StartingOffset - Offset in the stream to begin the read.
1514
1515 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1516 to this point. We will stop early if we exceed the maximum number
1517 of parallel Ios we support.
1518
1519 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1520 this routine is called.
1521
1522 RunCount - Number of entries in the IoRuns array filled here.
1523
1524 ThisByteCount - Number of bytes described by the IoRun entries. Will
1525 not exceed the ByteCount passed in.
1526
1527 Return Value:
1528
1529 BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
1530 this is synchronous). FALSE otherwise.
1531
1532 --*/
1533
1534 {
1535 BOOLEAN FoundUnaligned = FALSE;
1536 PIO_RUN ThisIoRun = IoRuns;
1537
1538 //
1539 // Following indicate where we are in the current transfer. Current
1540 // position in the file and number of bytes yet to transfer from
1541 // this position.
1542 //
1543
1544 ULONG RemainingByteCount = ByteCount;
1545 LONGLONG CurrentFileOffset = StartingOffset;
1546
1547 //
1548 // Following indicate the state of the user's buffer. We have
1549 // the destination of the next transfer and its offset in the
1550 // buffer. We also have the next available position in the buffer
1551 // available for a scratch buffer. We will align this up to a sector
1552 // boundary.
1553 //
1554
1555 PVOID CurrentUserBuffer = UserBuffer;
1556 ULONG CurrentUserBufferOffset = UserBufferOffset;
1557
1558 //
1559 // The following is the next contiguous bytes on the disk to
1560 // transfer. Read from the allocation package.
1561 //
1562
1563 LONGLONG DiskOffset = 0;
1564 ULONG CurrentByteCount = RemainingByteCount;
1565
1566 PAGED_CODE();
1567
1568 //
1569 // Initialize the RunCount and ByteCount.
1570 //
1571
1572 *RunCount = 0;
1573 *ThisByteCount = 0;
1574
1575 //
1576 // Loop while there are more bytes to process or there are
1577 // available entries in the IoRun array.
1578 //
1579
1580 while (TRUE) {
1581
1582 *RunCount += 1;
1583
1584 //
1585 // Initialize the current position in the IoRuns array.
1586 // Find the user's buffer for this portion of the transfer.
1587 //
1588
1589 ThisIoRun->UserBuffer = CurrentUserBuffer;
1590
1591 //
1592 // Find the allocation information for the current offset in the
1593 // stream.
1594 //
1595
1596 CdLookupAllocation( IrpContext,
1597 Fcb,
1598 CurrentFileOffset,
1599 &DiskOffset,
1600 &CurrentByteCount );
1601
1602 //
1603 // Limit ourselves to the data requested.
1604 //
1605
1606 if (CurrentByteCount > RemainingByteCount) {
1607
1608 CurrentByteCount = RemainingByteCount;
1609 }
1610
1611 //
1612 // Handle the case where this is an unaligned transfer. The
1613 // following must all be true for this to be an aligned transfer.
1614 //
1615 // Disk offset on a 2048 byte boundary (Start of transfer)
1616 //
1617 // Byte count is a multiple of 2048 (Length of transfer)
1618 //
1619 // If the ByteCount is at least one sector then do the
1620 // unaligned transfer only for the tail. We can use the
1621 // user's buffer for the aligned portion.
1622 //
1623
1624 if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) ||
1625 (FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) &&
1626 (CurrentByteCount < SECTOR_SIZE))) {
1627
1628 NT_ASSERT( SafeNodeType(Fcb) != CDFS_NTC_FCB_INDEX);
1629
1630 //
1631 // If we can't wait then raise.
1632 //
1633
1634 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
1635
1636 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
1637 }
1638
1639 //
1640 // Remember the offset and the number of bytes out of
1641 // the transfer buffer to copy into the user's buffer.
1642 // We will truncate the current read to end on a sector
1643 // boundary.
1644 //
1645
1646 ThisIoRun->TransferBufferOffset = SectorOffset( DiskOffset );
1647
1648 //
1649 // Make sure this transfer ends on a sector boundary.
1650 //
1651
1652 ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset );
1653
1654 //
1655 // We need to allocate an auxilary buffer for the next sector.
1656 // Read up to a page containing the partial data.
1657 //
1658
1659 ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
1660
1661 if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
1662
1663 ThisIoRun->DiskByteCount = PAGE_SIZE;
1664 }
1665
1666 if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
1667
1668 CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
1669 }
1670
1671 ThisIoRun->TransferByteCount = CurrentByteCount;
1672
1673 //
1674 // Allocate a buffer for the non-aligned transfer.
1675 //
1676
1677 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
1678
1679 //
1680 // Allocate and build the Mdl to describe this buffer.
1681 //
1682
1683 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
1684 PAGE_SIZE,
1685 FALSE,
1686 FALSE,
1687 NULL );
1688
1689 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
1690
1691 if (ThisIoRun->TransferMdl == NULL) {
1692
1693 IrpContext->Irp->IoStatus.Information = 0;
1694 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1695 }
1696
1697 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
1698
1699 //
1700 // Remember we found an unaligned transfer.
1701 //
1702
1703 FoundUnaligned = TRUE;
1704
1705 //
1706 // Otherwise we use the buffer and Mdl from the original request.
1707 //
1708
1709 } else {
1710
1711 //
1712 // Truncate the read length to a sector-aligned value. We know
1713 // the length must be at least one sector or we wouldn't be
1714 // here now.
1715 //
1716
1717 CurrentByteCount = SectorTruncate( CurrentByteCount );
1718
1719 //
1720 // Read these sectors from the disk.
1721 //
1722
1723 ThisIoRun->DiskOffset = DiskOffset;
1724 ThisIoRun->DiskByteCount = CurrentByteCount;
1725
1726 //
1727 // Use the user's buffer and Mdl as our transfer buffer
1728 // and Mdl.
1729 //
1730
1731 ThisIoRun->TransferBuffer = CurrentUserBuffer;
1732 ThisIoRun->TransferMdl = Irp->MdlAddress;
1733 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
1734 CurrentUserBufferOffset,
1735 PVOID );
1736 }
1737
1738 //
1739 // Update our position in the transfer and the RunCount and
1740 // ByteCount for the user.
1741 //
1742
1743 RemainingByteCount -= CurrentByteCount;
1744
1745 //
1746 // Break out if no more positions in the IoRuns array or
1747 // we have all of the bytes accounted for.
1748 //
1749
1750 *ThisByteCount += CurrentByteCount;
1751
1752 if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
1753
1754 break;
1755 }
1756
1757 //
1758 // Update our pointers for the user's buffer.
1759 //
1760
1761 ThisIoRun += 1;
1762 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID );
1763 CurrentUserBufferOffset += CurrentByteCount;
1764 CurrentFileOffset += CurrentByteCount;
1765 }
1766
1767 return FoundUnaligned;
1768 }
1769
1770 \f
1771 //
1772 // Local support routine
1773 //
1774
1775 _Requires_lock_held_(_Global_critical_region_)
1776 VOID
1777 CdPrepareXABuffers (
1778 _In_ PIRP_CONTEXT IrpContext,
1779 _In_ PIRP Irp,
1780 _In_ PFCB Fcb,
1781 _In_reads_bytes_(ByteCount) PVOID UserBuffer,
1782 _In_ ULONG UserBufferOffset,
1783 _In_ LONGLONG StartingOffset,
1784 _In_ ULONG ByteCount,
1785 _Out_ PIO_RUN IoRuns,
1786 _Out_ PULONG RunCount,
1787 _Out_ PULONG ThisByteCount
1788 )
1789
1790 /*++
1791
1792 Routine Description:
1793
1794 This routine is the worker routine which looks up the individual runs
1795 of an IO request and stores an entry for it in the IoRuns array. The
1796 worker routine is for XA files where we need to convert the raw offset
1797 in the file to logical cooked sectors. We store one raw sector in
1798 the Vcb. If the current read is to that sector then we can simply copy
1799 whatever bytes are needed from that sector.
1800
1801 Arguments:
1802
1803 Irp - Originating Irp for this request.
1804
1805 Fcb - This is the Fcb for this data stream. It must be a data stream.
1806
1807 UserBuffer - Current position in the user's buffer.
1808
1809 UserBufferOffset - Offset of this buffer from the beginning of the user's
1810 buffer for the original request.
1811
1812 StartingOffset - Offset in the stream to begin the read.
1813
1814 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1815 to this point. We will stop early if we exceed the maximum number
1816 of parallel Ios we support.
1817
1818 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1819 this routine is called.
1820
1821 RunCount - Number of entries in the IoRuns array filled here.
1822
1823 ThisByteCount - Number of bytes described by the IoRun entries. Will
1824 not exceed the ByteCount passed in.
1825
1826 Return Value:
1827
1828 None
1829
1830 --*/
1831
1832 {
1833 PIO_RUN ThisIoRun = IoRuns;
1834 BOOLEAN PerformedCopy;
1835
1836 //
1837 // The following deal with where we are in the range of raw sectors.
1838 // Note that we will bias the input file offset by the RIFF header
1839 // to deal directly with the raw sectors.
1840 //
1841
1842 ULONG RawSectorOffset;
1843 ULONG RemainingRawByteCount = ByteCount;
1844 LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER );
1845
1846 //
1847 // The following is the offset into the cooked sectors for the file.
1848 //
1849
1850 LONGLONG CurrentCookedOffset;
1851 ULONG RemainingCookedByteCount;
1852
1853 //
1854 // Following indicate the state of the user's buffer. We have
1855 // the destination of the next transfer and its offset in the
1856 // buffer. We also have the next available position in the buffer
1857 // available for a scratch buffer.
1858 //
1859
1860 PVOID CurrentUserBuffer = UserBuffer;
1861 ULONG CurrentUserBufferOffset = UserBufferOffset;
1862
1863 //
1864 // The following is the next contiguous bytes on the disk to
1865 // transfer. These are represented by cooked byte offset and length.
1866 // We also compute the number of raw bytes in the current transfer.
1867 //
1868
1869 LONGLONG DiskOffset = 0;
1870 ULONG CurrentCookedByteCount = 0;
1871 ULONG CurrentRawByteCount;
1872
1873 PAGED_CODE();
1874
1875 //
1876 // We need to maintain our position as we walk through the sectors on the disk.
1877 // We keep separate values for the cooked offset as well as the raw offset.
1878 // These are initialized on sector boundaries and we move through these
1879 // the file sector-by-sector.
1880 //
1881 // Try to do 32-bit math.
1882 //
1883
1884 if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) {
1885
1886 //
1887 // Prefix/fast: Note that the following are safe since we only
1888 // take this path for 32bit offsets.
1889 //
1890
1891 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
1892
1893 #pragma prefast( suppress: __WARNING_RESULTOFSHIFTCASTTOLARGERSIZE, "This is fine beacuse raw sector size > sector shift" )
1894 CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
1895
1896 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
1897
1898 //
1899 // Otherwise we need to do 64-bit math (sigh).
1900 //
1901
1902 } else {
1903
1904 CurrentRawOffset /= RAW_SECTOR_SIZE;
1905
1906 CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;
1907
1908 CurrentRawOffset *= RAW_SECTOR_SIZE;
1909 }
1910
1911 //
1912 // Now compute the full number of sectors to be read. Count all of the raw
1913 // sectors that need to be read and convert to cooked bytes.
1914 //
1915
1916 RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
1917 CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;
1918
1919 RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;
1920
1921 //
1922 // Initialize the RunCount and ByteCount.
1923 //
1924
1925 *RunCount = 0;
1926 *ThisByteCount = 0;
1927
1928 //
1929 // Loop while there are more bytes to process or there are
1930 // available entries in the IoRun array.
1931 //
1932
1933 while (TRUE) {
1934
1935 PerformedCopy = FALSE;
1936 *RunCount += 1;
1937
1938 //
1939 // Initialize the current position in the IoRuns array. Find the
1940 // eventual destination in the user's buffer for this portion of the transfer.
1941 //
1942
1943 ThisIoRun->UserBuffer = CurrentUserBuffer;
1944
1945 //
1946 // Find the allocation information for the current offset in the
1947 // stream.
1948 //
1949
1950 CdLookupAllocation( IrpContext,
1951 Fcb,
1952 CurrentCookedOffset,
1953 &DiskOffset,
1954 &CurrentCookedByteCount );
1955 //
1956 // Maybe we got lucky and this is the same sector as in the
1957 // Vcb.
1958 //
1959
1960 if (DiskOffset == Fcb->Vcb->XADiskOffset) {
1961
1962 //
1963 // We will perform safe synchronization. Check again that
1964 // this is the correct sector.
1965 //
1966
1967 CdLockVcb( IrpContext, Fcb->Vcb );
1968
1969 if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
1970 (Fcb->Vcb->XASector != NULL)) {
1971
1972 //
1973 // Copy any bytes we can from the current sector.
1974 //
1975
1976 CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
1977
1978 //
1979 // Check whether we don't go to the end of the sector.
1980 //
1981
1982 if (CurrentRawByteCount > RemainingRawByteCount) {
1983
1984 CurrentRawByteCount = RemainingRawByteCount;
1985 }
1986
1987 RtlCopyMemory( CurrentUserBuffer,
1988 Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
1989 CurrentRawByteCount );
1990
1991 CdUnlockVcb( IrpContext, Fcb->Vcb );
1992
1993 //
1994 // Adjust the run count and pointer in the IoRuns array
1995 // to show that we didn't use a position.
1996 //
1997
1998 *RunCount -= 1;
1999 ThisIoRun -= 1;
2000
2001 //
2002 // Remember that we performed a copy operation.
2003 //
2004
2005 PerformedCopy = TRUE;
2006
2007 CurrentCookedByteCount = SECTOR_SIZE;
2008
2009 } else {
2010
2011 //
2012 // The safe test showed no available buffer. Drop down to common code to
2013 // perform the Io.
2014 //
2015
2016 CdUnlockVcb( IrpContext, Fcb->Vcb );
2017 }
2018 }
2019
2020 //
2021 // No work in this pass if we did a copy operation.
2022 //
2023
2024 if (!PerformedCopy) {
2025
2026 //
2027 // Limit ourselves by the number of remaining cooked bytes.
2028 //
2029
2030 if (CurrentCookedByteCount > RemainingCookedByteCount) {
2031
2032 CurrentCookedByteCount = RemainingCookedByteCount;
2033 }
2034
2035 ThisIoRun->DiskOffset = DiskOffset;
2036 ThisIoRun->TransferBufferOffset = RawSectorOffset;
2037
2038 //
2039 // We will always need to perform copy operations for XA files.
2040 // We allocate an auxillary buffer to read the start of the
2041 // transfer. Then we can use a range of the user's buffer to
2042 // perform the next range of the transfer. Finally we may
2043 // need to allocate a buffer for the tail of the transfer.
2044 //
2045 // We can use the user's buffer (at the current scratch buffer) if the
2046 // following are true:
2047 //
2048 // If we are to store the beginning of the raw sector in the user's buffer.
2049 // The current scratch buffer precedes the destination in the user's buffer
2050 // (and hence also lies within it)
2051 // There are enough bytes remaining in the buffer for at least one
2052 // raw sector.
2053 //
2054
2055 if ((RawSectorOffset == 0) &&
2056 (RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
2057
2058 //
2059 // We can use the scratch buffer. We must ensure we don't send down reads
2060 // greater than the device can handle, since the driver is unable to split
2061 // raw requests.
2062 //
2063
2064 if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {
2065
2066 CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
2067
2068 } else {
2069
2070 CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
2071 CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
2072 }
2073
2074 //
2075 // Now make sure we are within the page transfer limit.
2076 //
2077
2078 while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
2079 Fcb->Vcb->MaximumPhysicalPages ) {
2080
2081 CurrentRawByteCount -= RAW_SECTOR_SIZE;
2082 CurrentCookedByteCount -= SECTOR_SIZE;
2083 }
2084
2085 //
2086 // Trim the number of bytes to read if it won't fit into the current buffer. Take
2087 // account of the fact that we must read in whole raw sector multiples.
2088 //
2089
2090 while (RawSectorAlign( CurrentRawByteCount) > RemainingRawByteCount) {
2091
2092 CurrentRawByteCount -= RAW_SECTOR_SIZE;
2093 CurrentCookedByteCount -= SECTOR_SIZE;
2094 }
2095
2096 //
2097 // Now trim the maximum number of raw bytes to the remaining bytes.
2098 //
2099
2100 if (CurrentRawByteCount > RemainingRawByteCount) {
2101
2102 CurrentRawByteCount = RemainingRawByteCount;
2103 }
2104
2105 //
2106 // Update the IO run array. We point to the scratch buffer as
2107 // well as the buffer and Mdl in the original Irp.
2108 //
2109
2110 ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
2111
2112 //
2113 // Point to the user's buffer and Mdl for this transfer.
2114 //
2115
2116 ThisIoRun->TransferBuffer = CurrentUserBuffer;
2117 ThisIoRun->TransferMdl = Irp->MdlAddress;
2118 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
2119 CurrentUserBufferOffset,
2120 PVOID);
2121
2122 } else {
2123
2124 //
2125 // We need to determine the number of bytes to transfer and the
2126 // offset into this page to begin the transfer.
2127 //
2128 // We will transfer only one raw sector.
2129 //
2130
2131 ThisIoRun->DiskByteCount = SECTOR_SIZE;
2132
2133 CurrentCookedByteCount = SECTOR_SIZE;
2134
2135 ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
2136 ThisIoRun->TransferBufferOffset = RawSectorOffset;
2137
2138 if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {
2139
2140 ThisIoRun->TransferByteCount = RemainingRawByteCount;
2141 }
2142
2143 CurrentRawByteCount = ThisIoRun->TransferByteCount;
2144
2145 //
2146 // We need to allocate an auxillary buffer. We will allocate
2147 // a single page. Then we will build an Mdl to describe the buffer.
2148 //
2149
2150 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
2151
2152 //
2153 // Allocate and build the Mdl to describe this buffer.
2154 //
2155
2156 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
2157 PAGE_SIZE,
2158 FALSE,
2159 FALSE,
2160 NULL );
2161
2162 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
2163
2164 if (ThisIoRun->TransferMdl == NULL) {
2165
2166 IrpContext->Irp->IoStatus.Information = 0;
2167 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2168 }
2169
2170 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
2171 }
2172 }
2173
2174 //
2175 // Update the byte count for our caller.
2176 //
2177
2178 RemainingRawByteCount -= CurrentRawByteCount;
2179 *ThisByteCount += CurrentRawByteCount;
2180
2181 //
2182 // Break out if no more positions in the IoRuns array or
2183 // we have all of the bytes accounted for.
2184 //
2185
2186 if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
2187
2188 break;
2189 }
2190
2191 //
2192 // Update our local pointers to allow for the current range of bytes.
2193 //
2194
2195 ThisIoRun += 1;
2196
2197 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID );
2198 CurrentUserBufferOffset += CurrentRawByteCount;
2199
2200 RawSectorOffset = 0;
2201
2202 CurrentCookedOffset += CurrentCookedByteCount;
2203 RemainingCookedByteCount -= CurrentCookedByteCount;
2204 }
2205
2206 return;
2207 }
2208
2209 \f
2210 //
2211 // Local support routine
2212 //
2213
2214 BOOLEAN
2215 CdFinishBuffers (
2216 _In_ PIRP_CONTEXT IrpContext,
2217 _Inout_ PIO_RUN IoRuns,
2218 _In_ ULONG RunCount,
2219 _In_ BOOLEAN FinalCleanup,
2220 _In_ BOOLEAN SaveXABuffer
2221 )
2222
2223 /*++
2224
2225 Routine Description:
2226
2227 This routine is called to perform any data transferred required for
2228 unaligned Io or to perform the final cleanup of the IoRuns array.
2229
2230 In all cases this is where we will deallocate any buffer and mdl
2231 allocated to perform the unaligned transfer. If this is not the
2232 final cleanup then we also transfer the bytes to the user buffer
2233 and flush the hardware cache.
2234
2235 We walk backwards through the run array because we may be shifting data
2236 in the user's buffer. Typical case is where we allocated a buffer for
2237 the first part of a read and then used the user's buffer for the
2238 next section (but stored it at the beginning of the buffer.
2239
2240 Arguments:
2241
2242 IoRuns - Pointer to the IoRuns array.
2243
2244 RunCount - Number of entries in the IoRuns array filled here.
2245
2246 FinalCleanup - Indicates if we should be deallocating temporary buffers
2247 (TRUE) or transferring bytes for a unaligned transfers and
2248 deallocating the buffers (FALSE). Flush the system cache if
2249 transferring data.
2250
2251 SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
2252
2253 Return Value:
2254
2255 BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
2256
2257 --*/
2258
2259 {
2260 BOOLEAN FlushIoBuffers = FALSE;
2261
2262 ULONG RemainingEntries = RunCount;
2263 PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
2264 PVCB Vcb;
2265
2266 PAGED_CODE();
2267
2268 //
2269 // Walk through each entry in the IoRun array.
2270 //
2271
2272 while (RemainingEntries != 0) {
2273
2274 //
2275 // We only need to deal with the case of an unaligned transfer.
2276 //
2277
2278 if (ThisIoRun->TransferByteCount != 0) {
2279
2280 //
2281 // If not the final cleanup then transfer the data to the
2282 // user's buffer and remember that we will need to flush
2283 // the user's buffer to memory.
2284 //
2285
2286 if (!FinalCleanup) {
2287
2288 RtlCopyMemory( ThisIoRun->UserBuffer,
2289 Add2Ptr( ThisIoRun->TransferBuffer,
2290 ThisIoRun->TransferBufferOffset,
2291 PVOID ),
2292 ThisIoRun->TransferByteCount );
2293
2294 FlushIoBuffers = TRUE;
2295 }
2296
2297 //
2298 // Free any Mdl we may have allocated. If the Mdl isn't
2299 // present then we must have failed during the allocation
2300 // phase.
2301 //
2302
2303 if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
2304
2305 if (ThisIoRun->TransferMdl != NULL) {
2306
2307 IoFreeMdl( ThisIoRun->TransferMdl );
2308 }
2309
2310 //
2311 // Now free any buffer we may have allocated. If the Mdl
2312 // doesn't match the original Mdl then free the buffer.
2313 //
2314
2315 if (ThisIoRun->TransferBuffer != NULL) {
2316
2317 //
2318 // If this is the final buffer for an XA read then store this buffer
2319 // into the Vcb so that we will have it when reading any remaining
2320 // portion of this buffer.
2321 //
2322
2323 if (SaveXABuffer) {
2324
2325 Vcb = IrpContext->Vcb;
2326
2327 CdLockVcb( IrpContext, Vcb );
2328
2329 if (Vcb->XASector != NULL) {
2330
2331 CdFreePool( &Vcb->XASector );
2332 }
2333
2334 Vcb->XASector = ThisIoRun->TransferBuffer;
2335 Vcb->XADiskOffset = ThisIoRun->DiskOffset;
2336
2337 SaveXABuffer = FALSE;
2338
2339 CdUnlockVcb( IrpContext, Vcb );
2340
2341 //
2342 // Otherwise just free the buffer.
2343 //
2344
2345 } else {
2346
2347 CdFreePool( &ThisIoRun->TransferBuffer );
2348 }
2349 }
2350 }
2351 }
2352
2353 //
2354 // Now handle the case where we failed in the process
2355 // of allocating associated Irps and Mdls.
2356 //
2357
2358 if (ThisIoRun->SavedIrp != NULL) {
2359
2360 if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
2361
2362 IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
2363 }
2364
2365 IoFreeIrp( ThisIoRun->SavedIrp );
2366 }
2367
2368 //
2369 // Move to the previous IoRun entry.
2370 //
2371
2372 ThisIoRun -= 1;
2373 RemainingEntries -= 1;
2374 }
2375
2376 //
2377 // If we copied any data then flush the Io buffers.
2378 //
2379
2380 return FlushIoBuffers;
2381 }
2382
2383 // Tell prefast this is a completion routine.
2384 IO_COMPLETION_ROUTINE CdSyncCompletionRoutine;
2385
2386 NTSTATUS
2387 CdSyncCompletionRoutine (
2388 PDEVICE_OBJECT DeviceObject,
2389 PIRP Irp,
2390 PVOID Contxt
2391 )
2392
2393 /*++
2394
2395 Routine Description:
2396
2397 Completion routine for synchronizing back to dispatch.
2398
2399 Arguments:
2400
2401 Contxt - pointer to KEVENT.
2402
2403 Return Value:
2404
2405 STATUS_MORE_PROCESSING_REQUIRED
2406
2407 --*/
2408
2409 {
2410 PKEVENT Event = (PKEVENT)Contxt;
2411 _Analysis_assume_(Contxt != NULL);
2412
2413 UNREFERENCED_PARAMETER( Irp );
2414 UNREFERENCED_PARAMETER( DeviceObject );
2415
2416 KeSetEvent( Event, 0, FALSE );
2417
2418 //
2419 // We don't want IO to get our IRP and free it.
2420 //
2421
2422 return STATUS_MORE_PROCESSING_REQUIRED;
2423 }
2424
2425
2426 _Requires_lock_held_(_Global_critical_region_)
2427 VOID
2428 CdFreeDirCache (
2429 _In_ PIRP_CONTEXT IrpContext
2430 )
2431
2432 /*++
2433
2434 Routine Description:
2435
2436 Safely frees the sector cache buffer.
2437
2438 Arguments:
2439
2440 Return Value:
2441
2442 None.
2443
2444 --*/
2445
2446 {
2447 PAGED_CODE();
2448
2449 if (NULL != IrpContext->Vcb->SectorCacheBuffer) {
2450
2451 CdAcquireCacheForUpdate( IrpContext);
2452 CdFreePool( &IrpContext->Vcb->SectorCacheBuffer);
2453 CdReleaseCache( IrpContext);
2454 }
2455 }
2456
2457 _Requires_lock_held_(_Global_critical_region_)
2458 BOOLEAN
2459 CdReadDirDataThroughCache (
2460 _In_ PIRP_CONTEXT IrpContext,
2461 _In_ PIO_RUN Run
2462 )
2463
2464 /*++
2465
2466 Routine Description:
2467
2468 Reads blocks through the sector cache. If the data is present, then it
2469 is copied from memory. If not present, one of the cache chunks will be
2470 replaced with a chunk containing the requested region, and the data
2471 copied from there.
2472
2473 Only intended for reading *directory* blocks, for the purpose of pre-caching
2474 directory information, by reading a chunk of blocks which hopefully contains
2475 other directory blocks, rather than just the (usually) single block requested.
2476
2477 Arguments:
2478
2479 Run - description of extent required, and buffer to read into.
2480
2481 Return Value:
2482
2483 None. Raises on error.
2484
2485 --*/
2486
2487 {
2488 PVCB Vcb = IrpContext->Vcb;
2489 ULONG Lbn = SectorsFromLlBytes( Run->DiskOffset);
2490 ULONG Remaining = SectorsFromBytes( Run->DiskByteCount);
2491 PUCHAR UserBuffer = Run->TransferBuffer;
2492
2493 NTSTATUS Status;
2494 ULONG Found;
2495 ULONG BufferSectorOffset;
2496 ULONG StartBlock;
2497 ULONG EndBlock;
2498 ULONG Blocks;
2499
2500 PIO_STACK_LOCATION IrpSp;
2501 IO_STATUS_BLOCK Iosb;
2502
2503 PTRACK_DATA TrackData;
2504
2505 #if DBG
2506 BOOLEAN JustRead = FALSE;
2507 #endif
2508
2509 ULONG Index;
2510 PCD_SECTOR_CACHE_CHUNK Buffer;
2511 BOOLEAN Result = FALSE;
2512
2513 PAGED_CODE();
2514
2515 CdAcquireCacheForRead( IrpContext);
2516
2517 try {
2518
2519 //
2520 // Check the cache hasn't gone away due to volume verify failure (which
2521 // is the *only* reason it'll go away). If this is the case we raise
2522 // the same error any I/O would return if the cache weren't here.
2523 //
2524
2525 if (NULL == Vcb->SectorCacheBuffer) {
2526
2527 CdRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED);
2528 }
2529
2530 while (Remaining) {
2531
2532 Buffer = NULL;
2533
2534 //
2535 // Look to see if any portion is currently cached.
2536 //
2537
2538 for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) {
2539
2540 if ((Vcb->SecCacheChunks[ Index].BaseLbn != -1) &&
2541 (Vcb->SecCacheChunks[ Index].BaseLbn <= Lbn) &&
2542 ((Vcb->SecCacheChunks[ Index].BaseLbn + CD_SEC_CHUNK_BLOCKS) > Lbn)) {
2543
2544 Buffer = &Vcb->SecCacheChunks[ Index];
2545 break;
2546 }
2547 }
2548
2549 //
2550 // If we found any, copy it out and continue.
2551 //
2552
2553 if (NULL != Buffer) {
2554
2555 BufferSectorOffset = Lbn - Buffer->BaseLbn;
2556 Found = Min( CD_SEC_CHUNK_BLOCKS - BufferSectorOffset, Remaining);
2557
2558 RtlCopyMemory( UserBuffer,
2559 Buffer->Buffer + BytesFromSectors( BufferSectorOffset),
2560 BytesFromSectors( Found));
2561
2562 Remaining -= Found;
2563 UserBuffer += BytesFromSectors( Found);
2564 Lbn += Found;
2565 #if DBG
2566 //
2567 // Update stats. Don't count a hit if we've just read the data in.
2568 //
2569
2570 if (!JustRead) {
2571
2572 InterlockedIncrement( (LONG*)&Vcb->SecCacheHits);
2573 }
2574
2575 JustRead = FALSE;
2576 #endif
2577 continue;
2578 }
2579
2580 //
2581 // Missed the cache, so we need to read a new chunk. Take the cache
2582 // resource exclusive while we do so.
2583 //
2584
2585 CdReleaseCache( IrpContext);
2586 CdAcquireCacheForUpdate( IrpContext);
2587 #if DBG
2588 Vcb->SecCacheMisses += 1;
2589 #endif
2590 //
2591 // Select the chunk to replace and calculate the start block of the
2592 // chunk to cache. We cache blocks which start on Lbns aligned on
2593 // multiples of chunk size, treating block 16 (VRS start) as block
2594 // zero.
2595 //
2596
2597 Buffer = &Vcb->SecCacheChunks[ Vcb->SecCacheLRUChunkIndex];
2598
2599 StartBlock = Lbn - ((Lbn - 16) % CD_SEC_CHUNK_BLOCKS);
2600
2601 //
2602 // Make sure we don't try and read past end of the last track.
2603 //
2604
2605 TrackData = &Vcb->CdromToc->TrackData[(Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack + 1)];
2606
2607 SwapCopyUchar4( &EndBlock, &TrackData->Address );
2608
2609 Blocks = EndBlock - StartBlock;
2610
2611 if (Blocks > CD_SEC_CHUNK_BLOCKS) {
2612
2613 Blocks = CD_SEC_CHUNK_BLOCKS;
2614 }
2615
2616 if ((0 == Blocks) || (Lbn < 16)) {
2617
2618 CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER);
2619 }
2620
2621 //
2622 // Now build / send the read request.
2623 //
2624
2625 IoReuseIrp( Vcb->SectorCacheIrp, STATUS_SUCCESS);
2626
2627 KeClearEvent( &Vcb->SectorCacheEvent);
2628 Vcb->SectorCacheIrp->Tail.Overlay.Thread = PsGetCurrentThread();
2629
2630 //
2631 // Get a pointer to the stack location of the first driver which will be
2632 // invoked. This is where the function codes and the parameters are set.
2633 //
2634
2635 IrpSp = IoGetNextIrpStackLocation( Vcb->SectorCacheIrp);
2636 IrpSp->MajorFunction = (UCHAR) IRP_MJ_READ;
2637
2638 //
2639 // Build an MDL to describe the buffer.
2640 //
2641
2642 IoAllocateMdl( Buffer->Buffer,
2643 BytesFromSectors( Blocks),
2644 FALSE,
2645 FALSE,
2646 Vcb->SectorCacheIrp);
2647
2648 if (NULL == Vcb->SectorCacheIrp->MdlAddress) {
2649
2650 IrpContext->Irp->IoStatus.Information = 0;
2651 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES);
2652 }
2653
2654 //
2655 // We're reading/writing into the block cache (paged pool). Lock the
2656 // pages and update the MDL with physical page information.
2657 //
2658
2659 try {
2660
2661 MmProbeAndLockPages( Vcb->SectorCacheIrp->MdlAddress,
2662 KernelMode,
2663 (LOCK_OPERATION) IoWriteAccess );
2664 }
2665 #pragma warning(suppress: 6320)
2666 except(EXCEPTION_EXECUTE_HANDLER) {
2667
2668 IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress );
2669 Vcb->SectorCacheIrp->MdlAddress = NULL;
2670 }
2671
2672 if (NULL == Vcb->SectorCacheIrp->MdlAddress) {
2673
2674 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2675 }
2676
2677 //
2678 // Reset the BaseLbn as we can't trust this Buffer's data until the request
2679 // is successfully completed.
2680 //
2681
2682 Buffer->BaseLbn = (ULONG)-1;
2683
2684 IrpSp->Parameters.Read.Length = BytesFromSectors( Blocks);
2685 IrpSp->Parameters.Read.ByteOffset.QuadPart = LlBytesFromSectors( StartBlock);
2686
2687 IoSetCompletionRoutine( Vcb->SectorCacheIrp,
2688 CdSyncCompletionRoutine,
2689 &Vcb->SectorCacheEvent,
2690 TRUE,
2691 TRUE,
2692 TRUE );
2693
2694 Vcb->SectorCacheIrp->UserIosb = &Iosb;
2695
2696 Status = IoCallDriver( Vcb->TargetDeviceObject, Vcb->SectorCacheIrp );
2697
2698 if (STATUS_PENDING == Status) {
2699
2700
2701 (VOID)KeWaitForSingleObject( &Vcb->SectorCacheEvent,
2702 Executive,
2703 KernelMode,
2704 FALSE,
2705 NULL );
2706
2707 Status = Vcb->SectorCacheIrp->IoStatus.Status;
2708 }
2709
2710 Vcb->SectorCacheIrp->UserIosb = NULL;
2711
2712 //
2713 // Unlock the pages and free the MDL.
2714 //
2715
2716 MmUnlockPages( Vcb->SectorCacheIrp->MdlAddress );
2717 IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress );
2718 Vcb->SectorCacheIrp->MdlAddress = NULL;
2719
2720 if (!NT_SUCCESS( Status )) {
2721
2722 try_leave( Status );
2723 }
2724
2725 //
2726 // Update the buffer information, and drop the cache resource to shared
2727 // to allow in reads.
2728 //
2729
2730 Buffer->BaseLbn = StartBlock;
2731 Vcb->SecCacheLRUChunkIndex = (Vcb->SecCacheLRUChunkIndex + 1) % CD_SEC_CACHE_CHUNKS;
2732
2733 CdConvertCacheToShared( IrpContext);
2734 #if DBG
2735 JustRead = TRUE;
2736 #endif
2737 }
2738
2739 Result = TRUE;
2740 }
2741 finally {
2742
2743 CdReleaseCache( IrpContext);
2744 }
2745
2746 return Result;
2747 }
2748
2749
2750 //
2751 // Local support routine
2752 //
2753
2754 _Requires_lock_held_(_Global_critical_region_)
2755 VOID
2756 CdMultipleAsync (
2757 _In_ PIRP_CONTEXT IrpContext,
2758 _In_ PFCB Fcb,
2759 _In_ ULONG RunCount,
2760 _Inout_ PIO_RUN IoRuns
2761 )
2762
2763 /*++
2764
2765 Routine Description:
2766
2767 This routine first does the initial setup required of a Master IRP that is
2768 going to be completed using associated IRPs. This routine should not
2769 be used if only one async request is needed, instead the single read
2770 async routines should be called.
2771
2772 A context parameter is initialized, to serve as a communications area
2773 between here and the common completion routine.
2774
2775 Next this routine reads or writes one or more contiguous sectors from
2776 a device asynchronously, and is used if there are multiple reads for a
2777 master IRP. A completion routine is used to synchronize with the
2778 completion of all of the I/O requests started by calls to this routine.
2779
2780 Also, prior to calling this routine the caller must initialize the
2781 IoStatus field in the Context, with the correct success status and byte
2782 count which are expected if all of the parallel transfers complete
2783 successfully. After return this status will be unchanged if all requests
2784 were, in fact, successful. However, if one or more errors occur, the
2785 IoStatus will be modified to reflect the error status and byte count
2786 from the first run (by Vbo) which encountered an error. I/O status
2787 from all subsequent runs will not be indicated.
2788
2789 Arguments:
2790
2791 RunCount - Supplies the number of multiple async requests
2792 that will be issued against the master irp.
2793
2794 IoRuns - Supplies an array containing the Offset and ByteCount for the
2795 separate requests.
2796
2797 Return Value:
2798
2799 None.
2800
2801 --*/
2802
2803 {
2804 PIO_COMPLETION_ROUTINE CompletionRoutine;
2805 PIO_STACK_LOCATION IrpSp;
2806 PMDL Mdl;
2807 PIRP Irp;
2808 PIRP MasterIrp;
2809 ULONG UnwindRunCount;
2810 BOOLEAN UseSectorCache;
2811
2812 PAGED_CODE();
2813
2814 //
2815 // Set up things according to whether this is truely async.
2816 //
2817
2818 CompletionRoutine = CdMultiSyncCompletionRoutine;
2819
2820 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
2821
2822 CompletionRoutine = CdMultiAsyncCompletionRoutine;
2823 }
2824
2825 //
2826 // For directories, use the sector cache.
2827 //
2828
2829 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
2830 (NULL != Fcb->Vcb->SectorCacheBuffer) &&
2831 (VcbMounted == IrpContext->Vcb->VcbCondition)) {
2832
2833 UseSectorCache = TRUE;
2834 }
2835 else {
2836
2837 UseSectorCache = FALSE;
2838 }
2839
2840 //
2841 // Initialize some local variables.
2842 //
2843
2844 MasterIrp = IrpContext->Irp;
2845
2846 //
2847 // Itterate through the runs, doing everything that can fail.
2848 // We let the cleanup in CdFinishBuffers clean up on error.
2849 //
2850
2851 for (UnwindRunCount = 0;
2852 UnwindRunCount < RunCount;
2853 UnwindRunCount += 1) {
2854
2855 if (UseSectorCache) {
2856
2857 if (!CdReadDirDataThroughCache( IrpContext, &IoRuns[ UnwindRunCount])) {
2858
2859 //
2860 // Turn off using directory cache and restart all over again.
2861 //
2862
2863 UseSectorCache = FALSE;
2864 UnwindRunCount = 0;
2865 }
2866
2867 continue;
2868 }
2869
2870 //
2871 // Create an associated IRP, making sure there is one stack entry for
2872 // us, as well.
2873 //
2874
2875 IoRuns[UnwindRunCount].SavedIrp =
2876 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
2877
2878 if (Irp == NULL) {
2879
2880 IrpContext->Irp->IoStatus.Information = 0;
2881 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2882 }
2883
2884 //
2885 // Allocate and build a partial Mdl for the request.
2886 //
2887
2888 Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
2889 IoRuns[UnwindRunCount].DiskByteCount,
2890 FALSE,
2891 FALSE,
2892 Irp );
2893
2894 if (Mdl == NULL) {
2895
2896 IrpContext->Irp->IoStatus.Information = 0;
2897 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2898 }
2899
2900 IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
2901 Mdl,
2902 IoRuns[UnwindRunCount].TransferVirtualAddress,
2903 IoRuns[UnwindRunCount].DiskByteCount );
2904
2905 //
2906 // Get the first IRP stack location in the associated Irp
2907 //
2908
2909 IoSetNextIrpStackLocation( Irp );
2910 IrpSp = IoGetCurrentIrpStackLocation( Irp );
2911
2912 //
2913 // Setup the Stack location to describe our read.
2914 //
2915
2916 IrpSp->MajorFunction = IRP_MJ_READ;
2917 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
2918 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
2919
2920 //
2921 // Set up the completion routine address in our stack frame.
2922 //
2923
2924 IoSetCompletionRoutine( Irp,
2925 CompletionRoutine,
2926 IrpContext->IoContext,
2927 TRUE,
2928 TRUE,
2929 TRUE );
2930
2931 //
2932 // Setup the next IRP stack location in the associated Irp for the disk
2933 // driver beneath us.
2934 //
2935
2936 IrpSp = IoGetNextIrpStackLocation( Irp );
2937
2938 //
2939 // Setup the Stack location to do a read from the disk driver.
2940 //
2941
2942 IrpSp->MajorFunction = IRP_MJ_READ;
2943 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
2944 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
2945 }
2946
2947 //
2948 // If we used the cache, we're done.
2949 //
2950
2951 if (UseSectorCache) {
2952
2953 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
2954
2955 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
2956 KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE );
2957 }
2958
2959 return;
2960 }
2961
2962 //
2963 // We only need to set the associated IRP count in the master irp to
2964 // make it a master IRP. But we set the count to one more than our
2965 // caller requested, because we do not want the I/O system to complete
2966 // the I/O. We also set our own count.
2967 //
2968
2969 IrpContext->IoContext->IrpCount = RunCount;
2970 IrpContext->IoContext->MasterIrp = MasterIrp;
2971
2972 //
2973 // We set the count in the master Irp to 1 since typically we
2974 // will clean up the associated irps ourselves. Setting this to one
2975 // means completing the last associated Irp with SUCCESS (in the async
2976 // case) will complete the master irp.
2977 //
2978
2979 MasterIrp->AssociatedIrp.IrpCount = 1;
2980
2981 //
2982 // If we (FS) acquired locks, transition the lock owners to an object, since
2983 // when we return this thread could go away before request completion, and
2984 // the resource package may otherwise try to boost priority, etc.
2985 //
2986
2987 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ) &&
2988 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
2989
2990 NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() );
2991
2992 IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3;
2993
2994 ExSetResourceOwnerPointer( IrpContext->IoContext->Resource,
2995 (PVOID)IrpContext->IoContext->ResourceThreadId );
2996 }
2997
2998 //
2999 // Now that all the dangerous work is done, issue the Io requests
3000 //
3001
3002 for (UnwindRunCount = 0;
3003 UnwindRunCount < RunCount;
3004 UnwindRunCount++) {
3005
3006 Irp = IoRuns[UnwindRunCount].SavedIrp;
3007 IoRuns[UnwindRunCount].SavedIrp = NULL;
3008
3009 if (NULL != Irp) {
3010
3011 //
3012 // If IoCallDriver returns an error, it has completed the Irp
3013 // and the error will be caught by our completion routines
3014 // and dealt with as a normal IO error.
3015 //
3016
3017 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
3018 }
3019 }
3020 }
3021
3022 \f
3023 //
3024 // Local support routine
3025 //
3026
3027 VOID
3028 CdMultipleXAAsync (
3029 _In_ PIRP_CONTEXT IrpContext,
3030 _In_ ULONG RunCount,
3031 _Inout_ PIO_RUN IoRuns,
3032 _In_ PRAW_READ_INFO RawReads,
3033 _In_ TRACK_MODE_TYPE TrackMode
3034 )
3035
3036 /*++
3037
3038 Routine Description:
3039
3040 This routine first does the initial setup required of a Master IRP that is
3041 going to be completed using associated IRPs. This routine is used to generate
3042 the associated Irps used to read raw sectors from the disk.
3043
3044 A context parameter is initialized, to serve as a communications area
3045 between here and the common completion routine.
3046
3047 Next this routine reads or writes one or more contiguous sectors from
3048 a device asynchronously, and is used if there are multiple reads for a
3049 master IRP. A completion routine is used to synchronize with the
3050 completion of all of the I/O requests started by calls to this routine.
3051
3052 Also, prior to calling this routine the caller must initialize the
3053 IoStatus field in the Context, with the correct success status and byte
3054 count which are expected if all of the parallel transfers complete
3055 successfully. After return this status will be unchanged if all requests
3056 were, in fact, successful. However, if one or more errors occur, the
3057 IoStatus will be modified to reflect the error status and byte count
3058 from the first run (by Vbo) which encountered an error. I/O status
3059 from all subsequent runs will not be indicated.
3060
3061 Arguments:
3062
3063 RunCount - Supplies the number of multiple async requests
3064 that will be issued against the master irp.
3065
3066 IoRuns - Supplies an array containing the Offset and ByteCount for the
3067 separate requests.
3068
3069 RawReads - Supplies an array of structures to store in the Irps passed to the
3070 device driver to perform the low-level Io.
3071
3072 TrackMode - Supplies the recording mode of sectors in these IoRuns
3073
3074 Return Value:
3075
3076 None.
3077
3078 --*/
3079
3080 {
3081 PIO_STACK_LOCATION IrpSp;
3082 PMDL Mdl;
3083 PIRP Irp;
3084 PIRP MasterIrp;
3085 ULONG UnwindRunCount;
3086 ULONG RawByteCount;
3087
3088 PIO_RUN ThisIoRun = IoRuns;
3089 PRAW_READ_INFO ThisRawRead = RawReads;
3090
3091 PAGED_CODE();
3092
3093 //
3094 // Initialize some local variables.
3095 //
3096
3097 MasterIrp = IrpContext->Irp;
3098
3099 //
3100 // Itterate through the runs, doing everything that can fail.
3101 // We let the cleanup in CdFinishBuffers clean up on error.
3102 //
3103
3104 for (UnwindRunCount = 0;
3105 UnwindRunCount < RunCount;
3106 UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) {
3107
3108 //
3109 // Create an associated IRP, making sure there is one stack entry for
3110 // us, as well.
3111 //
3112
3113 ThisIoRun->SavedIrp =
3114 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
3115
3116 if (Irp == NULL) {
3117
3118 IrpContext->Irp->IoStatus.Information = 0;
3119 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
3120 }
3121
3122 //
3123 // Should have been passed a byte count of at least one sector, and
3124 // must be a multiple of sector size
3125 //
3126
3127 NT_ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
3128
3129 RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
3130
3131 //
3132 // Allocate and build a partial Mdl for the request.
3133 //
3134
3135 Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress,
3136 RawByteCount,
3137 FALSE,
3138 FALSE,
3139 Irp );
3140
3141 if (Mdl == NULL) {
3142
3143 IrpContext->Irp->IoStatus.Information = 0;
3144 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
3145 }
3146
3147 IoBuildPartialMdl( ThisIoRun->TransferMdl,
3148 Mdl,
3149 ThisIoRun->TransferVirtualAddress,
3150 RawByteCount);
3151 //
3152 // Get the first IRP stack location in the associated Irp
3153 //
3154
3155 IoSetNextIrpStackLocation( Irp );
3156 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3157
3158 //
3159 // Setup the Stack location to describe our read (using cooked values)
3160 // These values won't be used for the raw read in any case.
3161 //
3162
3163 IrpSp->MajorFunction = IRP_MJ_READ;
3164 IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount;
3165 IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset;
3166
3167 //
3168 // Set up the completion routine address in our stack frame.
3169 //
3170
3171 IoSetCompletionRoutine( Irp,
3172 CdMultiSyncCompletionRoutine,
3173 IrpContext->IoContext,
3174 TRUE,
3175 TRUE,
3176 TRUE );
3177
3178 //
3179 // Setup the next IRP stack location in the associated Irp for the disk
3180 // driver beneath us.
3181 //
3182
3183 IrpSp = IoGetNextIrpStackLocation( Irp );
3184
3185 //
3186 // Setup the stack location to do a read of raw sectors at this location.
3187 // Note that the storage stack always reads multiples of whole XA sectors.
3188 //
3189
3190 ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset;
3191 ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT;
3192 ThisRawRead->TrackMode = TrackMode;
3193
3194 IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
3195
3196 IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE;
3197 Irp->UserBuffer = ThisIoRun->TransferVirtualAddress;
3198
3199 IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO );
3200 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead;
3201
3202 IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ;
3203 }
3204
3205 //
3206 // We only need to set the associated IRP count in the master irp to
3207 // make it a master IRP. But we set the count to one more than our
3208 // caller requested, because we do not want the I/O system to complete
3209 // the I/O. We also set our own count.
3210 //
3211
3212 IrpContext->IoContext->IrpCount = RunCount;
3213 IrpContext->IoContext->MasterIrp = MasterIrp;
3214
3215 //
3216 // We set the count in the master Irp to 1 since typically we
3217 // will clean up the associated irps ourselves. Setting this to one
3218 // means completing the last associated Irp with SUCCESS (in the async
3219 // case) will complete the master irp.
3220 //
3221
3222 MasterIrp->AssociatedIrp.IrpCount = 1;
3223
3224 //
3225 // Now that all the dangerous work is done, issue the Io requests
3226 //
3227
3228 for (UnwindRunCount = 0;
3229 UnwindRunCount < RunCount;
3230 UnwindRunCount++) {
3231
3232 Irp = IoRuns[UnwindRunCount].SavedIrp;
3233 IoRuns[UnwindRunCount].SavedIrp = NULL;
3234
3235 //
3236 //
3237 // If IoCallDriver returns an error, it has completed the Irp
3238 // and the error will be caught by our completion routines
3239 // and dealt with as a normal IO error.
3240 //
3241
3242 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
3243 }
3244
3245 return;
3246 }
3247
3248 \f
3249 //
3250 // Local support routine
3251 //
3252
3253 _Requires_lock_held_(_Global_critical_region_)
3254 VOID
3255 CdSingleAsync (
3256 _In_ PIRP_CONTEXT IrpContext,
3257 _In_ PIO_RUN Run,
3258 _In_ PFCB Fcb
3259 )
3260
3261 /*++
3262
3263 Routine Description:
3264
3265 This routine reads one or more contiguous sectors from a device
3266 asynchronously, and is used if there is only one read necessary to
3267 complete the IRP. It implements the read by simply filling
3268 in the next stack frame in the Irp, and passing it on. The transfer
3269 occurs to the single buffer originally specified in the user request.
3270
3271 Arguments:
3272
3273 ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
3274
3275 ByteCount - Supplies the number of bytes to read from the device
3276
3277 Return Value:
3278
3279 None.
3280
3281 --*/
3282
3283 {
3284 PIO_STACK_LOCATION IrpSp;
3285 PIO_COMPLETION_ROUTINE CompletionRoutine;
3286
3287 PAGED_CODE();
3288
3289 //
3290 // For directories, look in the sector cache,
3291 //
3292
3293 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
3294 (NULL != Fcb->Vcb->SectorCacheBuffer) &&
3295 (VcbMounted == IrpContext->Vcb->VcbCondition)) {
3296
3297 if (CdReadDirDataThroughCache( IrpContext, Run )) {
3298
3299 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
3300
3301 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
3302 KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE );
3303 }
3304
3305 return;
3306 }
3307 }
3308
3309 //
3310 // Set up things according to whether this is truely async.
3311 //
3312
3313 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
3314
3315 CompletionRoutine = CdSingleSyncCompletionRoutine;
3316
3317 } else {
3318
3319 CompletionRoutine = CdSingleAsyncCompletionRoutine;
3320
3321 //
3322 // If we (FS) acquired locks, transition the lock owners to an object, since
3323 // when we return this thread could go away before request completion, and
3324 // the resource package may otherwise try to boost priority, etc.
3325 //
3326
3327 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
3328
3329 NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() );
3330
3331 IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3;
3332
3333 ExSetResourceOwnerPointer( IrpContext->IoContext->Resource,
3334 (PVOID)IrpContext->IoContext->ResourceThreadId );
3335 }
3336 }
3337
3338 //
3339 // Set up the completion routine address in our stack frame.
3340 //
3341
3342 IoSetCompletionRoutine( IrpContext->Irp,
3343 CompletionRoutine,
3344 IrpContext->IoContext,
3345 TRUE,
3346 TRUE,
3347 TRUE );
3348
3349 //
3350 // Setup the next IRP stack location in the associated Irp for the disk
3351 // driver beneath us.
3352 //
3353
3354 IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp );
3355
3356 //
3357 // Setup the Stack location to do a read from the disk driver.
3358 //
3359
3360 IrpSp->MajorFunction = IrpContext->MajorFunction;
3361 IrpSp->Parameters.Read.Length = Run->DiskByteCount;
3362 IrpSp->Parameters.Read.ByteOffset.QuadPart = Run->DiskOffset;
3363
3364 //
3365 // Issue the Io request
3366 //
3367
3368 //
3369 // If IoCallDriver returns an error, it has completed the Irp
3370 // and the error will be caught by our completion routines
3371 // and dealt with as a normal IO error.
3372 //
3373
3374 (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
3375 }
3376
3377 \f
3378 //
3379 // Local support routine
3380 //
3381
3382 VOID
3383 CdWaitSync (
3384 _In_ PIRP_CONTEXT IrpContext
3385 )
3386
3387 /*++
3388
3389 Routine Description:
3390
3391 This routine waits for one or more previously started I/O requests
3392 from the above routines, by simply waiting on the event.
3393
3394 Arguments:
3395
3396 Return Value:
3397
3398 None
3399
3400 --*/
3401
3402 {
3403 PAGED_CODE();
3404
3405
3406 (VOID)KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
3407 Executive,
3408 KernelMode,
3409 FALSE,
3410 NULL );
3411
3412 KeClearEvent( &IrpContext->IoContext->SyncEvent );
3413 }
3414
3415 \f
3416 //
3417 // Local support routine
3418 //
3419
3420 NTSTATUS
3421 CdMultiSyncCompletionRoutine (
3422 PDEVICE_OBJECT DeviceObject,
3423 PIRP Irp,
3424 PVOID Context
3425 )
3426
3427 /*++
3428
3429 Routine Description:
3430
3431 This is the completion routine for all synchronous reads
3432 started via CdMultipleAsynch.
3433
3434 The completion routine has has the following responsibilities:
3435
3436 If the individual request was completed with an error, then
3437 this completion routine must see if this is the first error
3438 and remember the error status in the Context.
3439
3440 If the IrpCount goes to 1, then it sets the event in the Context
3441 parameter to signal the caller that all of the asynch requests
3442 are done.
3443
3444 Arguments:
3445
3446 DeviceObject - Pointer to the file system device object.
3447
3448 Irp - Pointer to the associated Irp which is being completed. (This
3449 Irp will no longer be accessible after this routine returns.)
3450
3451 Context - The context parameter which was specified for all of
3452 the multiple asynch I/O requests for this MasterIrp.
3453
3454 Return Value:
3455
3456 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3457 immediately complete the Master Irp without being in a race condition
3458 with the IoCompleteRequest thread trying to decrement the IrpCount in
3459 the Master Irp.
3460
3461 --*/
3462
3463 {
3464 PCD_IO_CONTEXT IoContext = Context;
3465 _Analysis_assume_(Context != NULL);
3466
3467 AssertVerifyDeviceIrp( Irp );
3468
3469 //
3470 // If we got an error (or verify required), remember it in the Irp
3471 //
3472
3473 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3474
3475 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
3476 IoContext->MasterIrp->IoStatus.Information = 0;
3477 }
3478
3479 //
3480 // We must do this here since IoCompleteRequest won't get a chance
3481 // on this associated Irp.
3482 //
3483
3484 IoFreeMdl( Irp->MdlAddress );
3485 IoFreeIrp( Irp );
3486
3487 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
3488
3489 //
3490 // Update the Master Irp with any error status from the associated Irps.
3491 //
3492
3493 IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
3494 KeSetEvent( &IoContext->SyncEvent, 0, FALSE );
3495 }
3496
3497 UNREFERENCED_PARAMETER( DeviceObject );
3498
3499 return STATUS_MORE_PROCESSING_REQUIRED;
3500 }
3501
3502 \f
3503 //
3504 // Local support routine
3505 //
3506
3507 NTSTATUS
3508 CdMultiAsyncCompletionRoutine (
3509 PDEVICE_OBJECT DeviceObject,
3510 PIRP Irp,
3511 PVOID Context
3512 )
3513
3514 /*++
3515
3516 Routine Description:
3517
3518 This is the completion routine for all asynchronous reads
3519 started via CdMultipleAsynch.
3520
3521 The completion routine has has the following responsibilities:
3522
3523 If the individual request was completed with an error, then
3524 this completion routine must see if this is the first error
3525 and remember the error status in the Context.
3526
3527 Arguments:
3528
3529 DeviceObject - Pointer to the file system device object.
3530
3531 Irp - Pointer to the associated Irp which is being completed. (This
3532 Irp will no longer be accessible after this routine returns.)
3533
3534 Context - The context parameter which was specified for all of
3535 the multiple asynch I/O requests for this MasterIrp.
3536
3537 Return Value:
3538
3539 Currently always returns STATUS_SUCCESS.
3540
3541 --*/
3542
3543 {
3544 PCD_IO_CONTEXT IoContext = Context;
3545 _Analysis_assume_(Context != NULL);
3546 AssertVerifyDeviceIrp( Irp );
3547
3548 UNREFERENCED_PARAMETER( DeviceObject );
3549
3550 //
3551 // If we got an error (or verify required), remember it in the Irp
3552 //
3553
3554 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3555
3556 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
3557 }
3558
3559 //
3560 // Decrement IrpCount and see if it goes to zero.
3561 //
3562
3563 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
3564
3565 //
3566 // Mark the master Irp pending
3567 //
3568
3569 IoMarkIrpPending( IoContext->MasterIrp );
3570
3571 //
3572 // Update the Master Irp with any error status from the associated Irps.
3573 //
3574
3575 IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
3576
3577 //
3578 // Update the information field with the correct value.
3579 //
3580
3581 IoContext->MasterIrp->IoStatus.Information = 0;
3582
3583 if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) {
3584
3585 IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount;
3586 }
3587
3588 //
3589 // Now release the resource
3590 //
3591
3592 _Analysis_assume_lock_held_(*IoContext->Resource);
3593 ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId );
3594
3595 //
3596 // and finally, free the context record.
3597 //
3598
3599 CdFreeIoContext( IoContext );
3600
3601 //
3602 // Return success in this case.
3603 //
3604
3605 return STATUS_SUCCESS;
3606
3607 } else {
3608
3609 //
3610 // We need to cleanup the associated Irp and its Mdl.
3611 //
3612
3613 IoFreeMdl( Irp->MdlAddress );
3614 IoFreeIrp( Irp );
3615
3616 return STATUS_MORE_PROCESSING_REQUIRED;
3617 }
3618
3619 }
3620
3621 \f
3622 //
3623 // Local support routine
3624 //
3625
3626 NTSTATUS
3627 CdSingleSyncCompletionRoutine (
3628 PDEVICE_OBJECT DeviceObject,
3629 PIRP Irp,
3630 PVOID Context
3631 )
3632
3633 /*++
3634
3635 Routine Description:
3636
3637 This is the completion routine for all reads started via CdSingleAsynch.
3638
3639 The completion routine has has the following responsibilities:
3640
3641 It sets the event in the Context parameter to signal the caller
3642 that all of the asynch requests are done.
3643
3644 Arguments:
3645
3646 DeviceObject - Pointer to the file system device object.
3647
3648 Irp - Pointer to the Irp for this request. (This Irp will no longer
3649 be accessible after this routine returns.)
3650
3651 Context - The context parameter which was specified in the call to
3652 CdSingleAsynch.
3653
3654 Return Value:
3655
3656 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3657 immediately complete the Master Irp without being in a race condition
3658 with the IoCompleteRequest thread trying to decrement the IrpCount in
3659 the Master Irp.
3660
3661 --*/
3662
3663 {
3664 _Analysis_assume_(Context != NULL);
3665
3666 UNREFERENCED_PARAMETER( DeviceObject );
3667
3668 AssertVerifyDeviceIrp( Irp );
3669
3670 //
3671 // Store the correct information field into the Irp.
3672 //
3673
3674 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3675
3676 Irp->IoStatus.Information = 0;
3677 }
3678
3679 KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE );
3680
3681 return STATUS_MORE_PROCESSING_REQUIRED;
3682 }
3683
3684 \f
3685 //
3686 // Local support routine
3687 //
3688
3689 NTSTATUS
3690 CdSingleAsyncCompletionRoutine (
3691 PDEVICE_OBJECT DeviceObject,
3692 PIRP Irp,
3693 PVOID Context
3694 )
3695
3696 /*++
3697
3698 Routine Description:
3699
3700 This is the completion routine for all asynchronous reads
3701 started via CdSingleAsynch.
3702
3703 Arguments:
3704
3705 DeviceObject - Pointer to the file system device object.
3706
3707 Irp - Pointer to the Irp for this request. (This Irp will no longer
3708 be accessible after this routine returns.)
3709
3710 Context - The context parameter which was specified in the call to
3711 CdSingleAsynch.
3712
3713 Return Value:
3714
3715 Currently always returns STATUS_SUCCESS.
3716
3717 --*/
3718
3719 {
3720 PCD_IO_CONTEXT IoContext = Context;
3721
3722 UNREFERENCED_PARAMETER( DeviceObject );
3723
3724 _Analysis_assume_(IoContext != NULL);
3725 AssertVerifyDeviceIrp( Irp );
3726
3727 //
3728 // Update the information field with the correct value for bytes read.
3729 //
3730
3731 Irp->IoStatus.Information = 0;
3732
3733 if (NT_SUCCESS( Irp->IoStatus.Status )) {
3734
3735 Irp->IoStatus.Information = IoContext->RequestedByteCount;
3736 }
3737
3738 //
3739 // Mark the Irp pending
3740 //
3741
3742 IoMarkIrpPending( Irp );
3743
3744 //
3745 // Now release the resource
3746 //
3747
3748 _Analysis_assume_lock_held_(*IoContext->Resource);
3749 ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId );
3750
3751 //
3752 // and finally, free the context record.
3753 //
3754
3755 CdFreeIoContext( IoContext );
3756 return STATUS_SUCCESS;
3757
3758 }
3759
3760 \f
3761 //
3762 // Local support routine
3763 //
3764
3765 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT))))
3766 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE)))
3767 VOID
3768 CdReadAudioSystemFile (
3769 _In_ PIRP_CONTEXT IrpContext,
3770 _In_ PFCB Fcb,
3771 _In_ LONGLONG StartingOffset,
3772 _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount,
3773 _Out_writes_bytes_(ByteCount) PVOID SystemBuffer
3774 )
3775
3776 /*++
3777
3778 Routine Description:
3779
3780 This routine is called to read the pseudo root directory and path
3781 table for a music disk. We build the individual elements on the
3782 stack and copy into the cache buffer.
3783
3784 Arguments:
3785
3786 Fcb - Fcb representing the file to read.
3787
3788 StartingOffset - Logical offset in the file to read from.
3789
3790 ByteCount - Number of bytes to read.
3791
3792 SystemBuffer - Pointer to buffer to fill in. This will always be page
3793 aligned.
3794
3795 Return Value:
3796
3797 None.
3798
3799 --*/
3800
3801 {
3802 PRAW_PATH_ISO RawPath;
3803 PRAW_DIRENT RawDirent;
3804
3805 ULONG CurrentTrack;
3806 ULONG SectorOffset;
3807 ULONG EntryCount;
3808 UCHAR TrackOnes;
3809 UCHAR TrackTens;
3810 PTRACK_DATA ThisTrack;
3811
3812 LONGLONG CurrentOffset;
3813
3814 PVOID CurrentSector;
3815
3816 PSYSTEM_USE_XA SystemUse;
3817
3818 ULONG BytesToCopy;
3819
3820 UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12];
3821
3822 PAGED_CODE();
3823
3824 //
3825 // If this is the path table then we just need a single entry.
3826 //
3827
3828 if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) {
3829
3830 //
3831 // Sanity check that the offset is zero.
3832 //
3833
3834 NT_ASSERT( StartingOffset == 0 );
3835
3836 //
3837 // Store a pseudo path entry in our local buffer.
3838 //
3839
3840 RawPath = (PRAW_PATH_ISO) LocalBuffer;
3841
3842 RtlZeroMemory( RawPath, sizeof( LocalBuffer ));
3843
3844 RawPath->DirIdLen = 1;
3845 RawPath->ParentNum = 1;
3846 RawPath->DirId[0] = '\0';
3847
3848 //
3849 // Now copy to the user's buffer.
3850 //
3851
3852 BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2;
3853
3854 if (BytesToCopy > ByteCount) {
3855
3856 BytesToCopy = ByteCount;
3857 }
3858
3859 RtlCopyMemory( SystemBuffer,
3860 RawPath,
3861 BytesToCopy );
3862
3863 //
3864 // We need to deal with the multiple sector case for the root directory.
3865 //
3866
3867 } else {
3868
3869 //
3870 // Initialize the first track to return to our caller.
3871 //
3872
3873 CurrentTrack = 0;
3874
3875 //
3876 // If the offset is zero then store the entries for the self and parent
3877 // entries.
3878 //
3879
3880 if (StartingOffset == 0) {
3881
3882 RawDirent = SystemBuffer;
3883
3884 //
3885 // Clear all of the fields initially.
3886 //
3887
3888 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
3889
3890 //
3891 // Now fill in the interesting fields.
3892 //
3893
3894 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
3895 RawDirent->FileIdLen = 1;
3896 RawDirent->FileId[0] = '\0';
3897 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
3898
3899 //
3900 // Set the time stamp to be Jan 1, 1995
3901 //
3902
3903 RawDirent->RecordTime[0] = 95;
3904 RawDirent->RecordTime[1] = 1;
3905 RawDirent->RecordTime[2] = 1;
3906
3907 SectorOffset = RawDirent->DirLen;
3908
3909 RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT );
3910
3911 //
3912 // Clear all of the fields initially.
3913 //
3914
3915 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
3916
3917 //
3918 // Now fill in the interesting fields.
3919 //
3920
3921 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
3922 RawDirent->FileIdLen = 1;
3923 RawDirent->FileId[0] = '\1';
3924 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
3925
3926 //
3927 // Set the time stamp to be Jan 1, 1995
3928 //
3929
3930 RawDirent->RecordTime[0] = 95;
3931 RawDirent->RecordTime[1] = 1;
3932 RawDirent->RecordTime[2] = 1;
3933
3934 SectorOffset += RawDirent->DirLen;
3935 EntryCount = 2;
3936
3937 //
3938 // Otherwise compute the starting track to write to the buffer.
3939 //
3940
3941 } else {
3942
3943 //
3944 // Count the tracks in each preceding sector.
3945 //
3946
3947 CurrentOffset = 0;
3948
3949 do {
3950
3951 CurrentTrack += CdAudioDirentsPerSector;
3952 CurrentOffset += SECTOR_SIZE;
3953
3954 } while (CurrentOffset < StartingOffset);
3955
3956 //
3957 // Bias the track count to reflect the two default entries.
3958 //
3959
3960 CurrentTrack -= 2;
3961
3962 SectorOffset = 0;
3963 EntryCount = 0;
3964 }
3965
3966 //
3967 // We now know the first track to return as well as where we are in
3968 // the current sector. We will walk through sector by sector adding
3969 // the entries for the separate tracks in the TOC. We will zero
3970 // any sectors or partial sectors without data.
3971 //
3972
3973 CurrentSector = SystemBuffer;
3974 BytesToCopy = SECTOR_SIZE;
3975
3976 //
3977 // Loop for each sector.
3978 //
3979
3980 do {
3981
3982 //
3983 // Add entries until we reach our threshold for each sector.
3984 //
3985
3986 do {
3987
3988 //
3989 // If we are beyond the entries in the TOC then exit.
3990 //
3991
3992 if (CurrentTrack >= IrpContext->Vcb->TrackCount) {
3993
3994 break;
3995 }
3996
3997 ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack];
3998
3999 //
4000 // Point to the current position in the buffer.
4001 //
4002
4003 RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT );
4004
4005 //
4006 // Clear all of the fields initially.
4007 //
4008
4009 RtlZeroMemory( RawDirent, CdAudioDirentSize );
4010
4011 //
4012 // Now fill in the interesting fields.
4013 //
4014
4015 RawDirent->DirLen = (UCHAR) CdAudioDirentSize;
4016 RawDirent->FileIdLen = CdAudioFileNameLength;
4017
4018 RtlCopyMemory( RawDirent->FileId,
4019 CdAudioFileName,
4020 CdAudioFileNameLength );
4021
4022 //
4023 // Set the time stamp to be Jan 1, 1995 00:00
4024 //
4025
4026 RawDirent->RecordTime[0] = 95;
4027 RawDirent->RecordTime[1] = 1;
4028 RawDirent->RecordTime[2] = 1;
4029
4030 //
4031 // Put the track number into the file name.
4032 //
4033
4034 TrackTens = TrackOnes = ThisTrack->TrackNumber;
4035
4036 TrackOnes = (TrackOnes % 10) + '0';
4037
4038 TrackTens /= 10;
4039 TrackTens = (TrackTens % 10) + '0';
4040
4041 RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens;
4042 RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes;
4043
4044 SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA );
4045
4046 SystemUse->Attributes = SYSTEM_USE_XA_DA;
4047 SystemUse->Signature = SYSTEM_XA_SIGNATURE;
4048
4049 //
4050 // Store the track number as the file number.
4051 //
4052
4053 SystemUse->FileNumber = (UCHAR) CurrentTrack;
4054
4055 EntryCount += 1;
4056 SectorOffset += CdAudioDirentSize;
4057 CurrentTrack += 1;
4058
4059 } while (EntryCount < CdAudioDirentsPerSector);
4060
4061 //
4062 // Zero the remaining portion of this buffer.
4063 //
4064
4065 RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ),
4066 SECTOR_SIZE - SectorOffset );
4067
4068 //
4069 // Prepare for the next sector.
4070 //
4071
4072 EntryCount = 0;
4073 BytesToCopy += SECTOR_SIZE;
4074 SectorOffset = 0;
4075 CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID );
4076
4077 } while (BytesToCopy <= ByteCount);
4078 }
4079
4080 return;
4081 }
4082
4083
4084 NTSTATUS
4085 CdHijackIrpAndFlushDevice (
4086 _In_ PIRP_CONTEXT IrpContext,
4087 _Inout_ PIRP Irp,
4088 _In_ PDEVICE_OBJECT TargetDeviceObject
4089 )
4090
4091 /*++
4092
4093 Routine Description:
4094
4095 This routine is called when we need to send a flush to a device but
4096 we don't have a flush Irp. What this routine does is make a copy
4097 of its current Irp stack location, but changes the Irp Major code
4098 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
4099 the knees in the completion routine, fix it up and return to the
4100 user as if nothing had happened.
4101
4102 Arguments:
4103
4104 Irp - The Irp to hijack
4105
4106 TargetDeviceObject - The device to send the request to.
4107
4108 Return Value:
4109
4110 NTSTATUS - The Status from the flush in case anybody cares.
4111
4112 --*/
4113
4114 {
4115 KEVENT Event;
4116 NTSTATUS Status;
4117 PIO_STACK_LOCATION NextIrpSp;
4118
4119 PAGED_CODE();
4120
4121 UNREFERENCED_PARAMETER( IrpContext );
4122
4123 //
4124 // Get the next stack location, and copy over the stack location
4125 //
4126
4127 NextIrpSp = IoGetNextIrpStackLocation( Irp );
4128
4129 *NextIrpSp = *IoGetCurrentIrpStackLocation( Irp );
4130
4131 NextIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
4132 NextIrpSp->MinorFunction = 0;
4133
4134 //
4135 // Set up the completion routine
4136 //
4137
4138 KeInitializeEvent( &Event, NotificationEvent, FALSE );
4139
4140 IoSetCompletionRoutine( Irp,
4141 CdSyncCompletionRoutine,
4142 &Event,
4143 TRUE,
4144 TRUE,
4145 TRUE );
4146
4147 //
4148 // Send the request.
4149 //
4150
4151 Status = IoCallDriver( TargetDeviceObject, Irp );
4152
4153 if (Status == STATUS_PENDING) {
4154
4155 (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
4156
4157 Status = Irp->IoStatus.Status;
4158 }
4159
4160 //
4161 // If the driver doesn't support flushes, return SUCCESS.
4162 //
4163
4164 if (Status == STATUS_INVALID_DEVICE_REQUEST) {
4165
4166 Status = STATUS_SUCCESS;
4167 }
4168
4169 Irp->IoStatus.Status = 0;
4170 Irp->IoStatus.Information = 0;
4171
4172 return Status;
4173 }
4174
4175