[CDFS_NEW] Re-apply many of the reactos-specific changes and fix build.
[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 _SEH2_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 } _SEH2_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 } _SEH2_END;
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 _SEH2_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 } _SEH2_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 } _SEH2_END;
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 _SEH2_TRY {
1286
1287 MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
1288
1289 Status = STATUS_SUCCESS;
1290
1291 #ifdef _MSC_VER
1292 #pragma warning(suppress: 6320)
1293 #endif
1294 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1295
1296 Status = _SEH2_GetExceptionCode();
1297
1298 IoFreeMdl( Mdl );
1299 IrpContext->Irp->MdlAddress = NULL;
1300
1301 if (!FsRtlIsNtstatusExpected( Status )) {
1302
1303 Status = STATUS_INVALID_USER_BUFFER;
1304 }
1305 } _SEH2_END;
1306 }
1307
1308 //
1309 // Check if we are to raise or return
1310 //
1311
1312 if (Status != STATUS_SUCCESS) {
1313
1314 if (RaiseOnError) {
1315
1316 CdRaiseStatus( IrpContext, Status );
1317 }
1318 }
1319
1320 //
1321 // Return the status code.
1322 //
1323
1324 return Status;
1325 }
1326
1327 \f
1328 NTSTATUS
1329 CdPerformDevIoCtrlEx (
1330 _In_ PIRP_CONTEXT IrpContext,
1331 _In_ ULONG IoControlCode,
1332 _In_ PDEVICE_OBJECT Device,
1333 _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
1334 _In_ ULONG InputBufferLength,
1335 _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
1336 _In_ ULONG OutputBufferLength,
1337 _In_ BOOLEAN InternalDeviceIoControl,
1338 _In_ BOOLEAN OverrideVerify,
1339 _Out_opt_ PIO_STATUS_BLOCK Iosb
1340 )
1341
1342 /*++
1343
1344 Routine Description:
1345
1346 This routine is called to perform DevIoCtrl functions internally within
1347 the filesystem. We take the status from the driver and return it to our
1348 caller.
1349
1350 Arguments:
1351
1352 IoControlCode - Code to send to driver.
1353
1354 Device - This is the device to send the request to.
1355
1356 OutPutBuffer - Pointer to output buffer.
1357
1358 OutputBufferLength - Length of output buffer above.
1359
1360 InternalDeviceIoControl - Indicates if this is an internal or external
1361 Io control code.
1362
1363 OverrideVerify - Indicates if we should tell the driver not to return
1364 STATUS_VERIFY_REQUIRED for mount and verify.
1365
1366 Iosb - If specified, we return the results of the operation here.
1367
1368 Return Value:
1369
1370 NTSTATUS - Status returned by next lower driver.
1371
1372 --*/
1373
1374 {
1375 NTSTATUS Status;
1376 PIRP Irp;
1377 KEVENT Event;
1378 IO_STATUS_BLOCK LocalIosb;
1379 PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
1380
1381 PAGED_CODE();
1382
1383 UNREFERENCED_PARAMETER( IrpContext );
1384
1385 //
1386 // Check if the user gave us an Iosb.
1387 //
1388
1389 if (ARGUMENT_PRESENT( Iosb )) {
1390
1391 IosbToUse = Iosb;
1392 }
1393
1394 IosbToUse->Status = 0;
1395 IosbToUse->Information = 0;
1396
1397 KeInitializeEvent( &Event, NotificationEvent, FALSE );
1398
1399 Irp = IoBuildDeviceIoControlRequest( IoControlCode,
1400 Device,
1401 InputBuffer,
1402 InputBufferLength,
1403 OutputBuffer,
1404 OutputBufferLength,
1405 InternalDeviceIoControl,
1406 &Event,
1407 IosbToUse );
1408
1409 if (Irp == NULL) {
1410
1411 return STATUS_INSUFFICIENT_RESOURCES;
1412 }
1413
1414 if (OverrideVerify) {
1415
1416 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
1417 }
1418
1419 Status = IoCallDriver( Device, Irp );
1420
1421 //
1422 // We check for device not ready by first checking Status
1423 // and then if status pending was returned, the Iosb status
1424 // value.
1425 //
1426
1427 if (Status == STATUS_PENDING) {
1428
1429 (VOID) KeWaitForSingleObject( &Event,
1430 Executive,
1431 KernelMode,
1432 FALSE,
1433 (PLARGE_INTEGER)NULL );
1434
1435 Status = IosbToUse->Status;
1436 }
1437
1438 NT_ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
1439
1440 return Status;
1441 }
1442
1443
1444 NTSTATUS
1445 FASTCALL
1446 CdPerformDevIoCtrl (
1447 _In_ PIRP_CONTEXT IrpContext,
1448 _In_ ULONG IoControlCode,
1449 _In_ PDEVICE_OBJECT Device,
1450 _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
1451 _In_ ULONG OutputBufferLength,
1452 _In_ BOOLEAN InternalDeviceIoControl,
1453 _In_ BOOLEAN OverrideVerify,
1454 _Out_opt_ PIO_STATUS_BLOCK Iosb
1455 )
1456 {
1457 PAGED_CODE();
1458
1459 return CdPerformDevIoCtrlEx( IrpContext,
1460 IoControlCode,
1461 Device,
1462 NULL,
1463 0,
1464 OutputBuffer,
1465 OutputBufferLength,
1466 InternalDeviceIoControl,
1467 OverrideVerify,
1468 Iosb);
1469 }
1470
1471
1472 \f
1473 //
1474 // Local support routine
1475 //
1476
1477 _Requires_lock_held_(_Global_critical_region_)
1478 BOOLEAN
1479 CdPrepareBuffers (
1480 _In_ PIRP_CONTEXT IrpContext,
1481 _In_ PIRP Irp,
1482 _In_ PFCB Fcb,
1483 _In_reads_bytes_(ByteCount) PVOID UserBuffer,
1484 _In_ ULONG UserBufferOffset,
1485 _In_ LONGLONG StartingOffset,
1486 _In_ ULONG ByteCount,
1487 _Out_ PIO_RUN IoRuns,
1488 _Out_ PULONG RunCount,
1489 _Out_ PULONG ThisByteCount
1490 )
1491
1492 /*++
1493
1494 Routine Description:
1495
1496 This routine is the worker routine which looks up each run of an IO
1497 request and stores an entry for it in the IoRuns array. If the run
1498 begins on an unaligned disk boundary then we will allocate a buffer
1499 and Mdl for the unaligned portion and put it in the IoRuns entry.
1500
1501 This routine will raise CANT_WAIT if an unaligned transfer is encountered
1502 and this request can't wait.
1503
1504 Arguments:
1505
1506 Irp - Originating Irp for this request.
1507
1508 Fcb - This is the Fcb for this data stream. It may be a file, directory,
1509 path table or the volume file.
1510
1511 UserBuffer - Current position in the user's buffer.
1512
1513 UserBufferOffset - Offset from the start of the original user buffer.
1514
1515 StartingOffset - Offset in the stream to begin the read.
1516
1517 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1518 to this point. We will stop early if we exceed the maximum number
1519 of parallel Ios we support.
1520
1521 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1522 this routine is called.
1523
1524 RunCount - Number of entries in the IoRuns array filled here.
1525
1526 ThisByteCount - Number of bytes described by the IoRun entries. Will
1527 not exceed the ByteCount passed in.
1528
1529 Return Value:
1530
1531 BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
1532 this is synchronous). FALSE otherwise.
1533
1534 --*/
1535
1536 {
1537 BOOLEAN FoundUnaligned = FALSE;
1538 PIO_RUN ThisIoRun = IoRuns;
1539
1540 //
1541 // Following indicate where we are in the current transfer. Current
1542 // position in the file and number of bytes yet to transfer from
1543 // this position.
1544 //
1545
1546 ULONG RemainingByteCount = ByteCount;
1547 LONGLONG CurrentFileOffset = StartingOffset;
1548
1549 //
1550 // Following indicate the state of the user's buffer. We have
1551 // the destination of the next transfer and its offset in the
1552 // buffer. We also have the next available position in the buffer
1553 // available for a scratch buffer. We will align this up to a sector
1554 // boundary.
1555 //
1556
1557 PVOID CurrentUserBuffer = UserBuffer;
1558 ULONG CurrentUserBufferOffset = UserBufferOffset;
1559
1560 //
1561 // The following is the next contiguous bytes on the disk to
1562 // transfer. Read from the allocation package.
1563 //
1564
1565 LONGLONG DiskOffset = 0;
1566 ULONG CurrentByteCount = RemainingByteCount;
1567
1568 PAGED_CODE();
1569
1570 //
1571 // Initialize the RunCount and ByteCount.
1572 //
1573
1574 *RunCount = 0;
1575 *ThisByteCount = 0;
1576
1577 //
1578 // Loop while there are more bytes to process or there are
1579 // available entries in the IoRun array.
1580 //
1581
1582 while (TRUE) {
1583
1584 *RunCount += 1;
1585
1586 //
1587 // Initialize the current position in the IoRuns array.
1588 // Find the user's buffer for this portion of the transfer.
1589 //
1590
1591 ThisIoRun->UserBuffer = CurrentUserBuffer;
1592
1593 //
1594 // Find the allocation information for the current offset in the
1595 // stream.
1596 //
1597
1598 CdLookupAllocation( IrpContext,
1599 Fcb,
1600 CurrentFileOffset,
1601 &DiskOffset,
1602 &CurrentByteCount );
1603
1604 //
1605 // Limit ourselves to the data requested.
1606 //
1607
1608 if (CurrentByteCount > RemainingByteCount) {
1609
1610 CurrentByteCount = RemainingByteCount;
1611 }
1612
1613 //
1614 // Handle the case where this is an unaligned transfer. The
1615 // following must all be true for this to be an aligned transfer.
1616 //
1617 // Disk offset on a 2048 byte boundary (Start of transfer)
1618 //
1619 // Byte count is a multiple of 2048 (Length of transfer)
1620 //
1621 // If the ByteCount is at least one sector then do the
1622 // unaligned transfer only for the tail. We can use the
1623 // user's buffer for the aligned portion.
1624 //
1625
1626 if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) ||
1627 (FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) &&
1628 (CurrentByteCount < SECTOR_SIZE))) {
1629
1630 NT_ASSERT( SafeNodeType(Fcb) != CDFS_NTC_FCB_INDEX);
1631
1632 //
1633 // If we can't wait then raise.
1634 //
1635
1636 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
1637
1638 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
1639 }
1640
1641 //
1642 // Remember the offset and the number of bytes out of
1643 // the transfer buffer to copy into the user's buffer.
1644 // We will truncate the current read to end on a sector
1645 // boundary.
1646 //
1647
1648 ThisIoRun->TransferBufferOffset = SectorOffset( DiskOffset );
1649
1650 //
1651 // Make sure this transfer ends on a sector boundary.
1652 //
1653
1654 ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset );
1655
1656 //
1657 // We need to allocate an auxilary buffer for the next sector.
1658 // Read up to a page containing the partial data.
1659 //
1660
1661 ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
1662
1663 if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
1664
1665 ThisIoRun->DiskByteCount = PAGE_SIZE;
1666 }
1667
1668 if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
1669
1670 CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
1671 }
1672
1673 ThisIoRun->TransferByteCount = CurrentByteCount;
1674
1675 //
1676 // Allocate a buffer for the non-aligned transfer.
1677 //
1678
1679 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
1680
1681 //
1682 // Allocate and build the Mdl to describe this buffer.
1683 //
1684
1685 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
1686 PAGE_SIZE,
1687 FALSE,
1688 FALSE,
1689 NULL );
1690
1691 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
1692
1693 if (ThisIoRun->TransferMdl == NULL) {
1694
1695 IrpContext->Irp->IoStatus.Information = 0;
1696 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1697 }
1698
1699 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
1700
1701 //
1702 // Remember we found an unaligned transfer.
1703 //
1704
1705 FoundUnaligned = TRUE;
1706
1707 //
1708 // Otherwise we use the buffer and Mdl from the original request.
1709 //
1710
1711 } else {
1712
1713 //
1714 // Truncate the read length to a sector-aligned value. We know
1715 // the length must be at least one sector or we wouldn't be
1716 // here now.
1717 //
1718
1719 CurrentByteCount = SectorTruncate( CurrentByteCount );
1720
1721 //
1722 // Read these sectors from the disk.
1723 //
1724
1725 ThisIoRun->DiskOffset = DiskOffset;
1726 ThisIoRun->DiskByteCount = CurrentByteCount;
1727
1728 //
1729 // Use the user's buffer and Mdl as our transfer buffer
1730 // and Mdl.
1731 //
1732
1733 ThisIoRun->TransferBuffer = CurrentUserBuffer;
1734 ThisIoRun->TransferMdl = Irp->MdlAddress;
1735 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
1736 CurrentUserBufferOffset,
1737 PVOID );
1738 }
1739
1740 //
1741 // Update our position in the transfer and the RunCount and
1742 // ByteCount for the user.
1743 //
1744
1745 RemainingByteCount -= CurrentByteCount;
1746
1747 //
1748 // Break out if no more positions in the IoRuns array or
1749 // we have all of the bytes accounted for.
1750 //
1751
1752 *ThisByteCount += CurrentByteCount;
1753
1754 if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
1755
1756 break;
1757 }
1758
1759 //
1760 // Update our pointers for the user's buffer.
1761 //
1762
1763 ThisIoRun += 1;
1764 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID );
1765 CurrentUserBufferOffset += CurrentByteCount;
1766 CurrentFileOffset += CurrentByteCount;
1767 }
1768
1769 return FoundUnaligned;
1770 }
1771
1772 \f
1773 //
1774 // Local support routine
1775 //
1776
1777 _Requires_lock_held_(_Global_critical_region_)
1778 VOID
1779 CdPrepareXABuffers (
1780 _In_ PIRP_CONTEXT IrpContext,
1781 _In_ PIRP Irp,
1782 _In_ PFCB Fcb,
1783 _In_reads_bytes_(ByteCount) PVOID UserBuffer,
1784 _In_ ULONG UserBufferOffset,
1785 _In_ LONGLONG StartingOffset,
1786 _In_ ULONG ByteCount,
1787 _Out_ PIO_RUN IoRuns,
1788 _Out_ PULONG RunCount,
1789 _Out_ PULONG ThisByteCount
1790 )
1791
1792 /*++
1793
1794 Routine Description:
1795
1796 This routine is the worker routine which looks up the individual runs
1797 of an IO request and stores an entry for it in the IoRuns array. The
1798 worker routine is for XA files where we need to convert the raw offset
1799 in the file to logical cooked sectors. We store one raw sector in
1800 the Vcb. If the current read is to that sector then we can simply copy
1801 whatever bytes are needed from that sector.
1802
1803 Arguments:
1804
1805 Irp - Originating Irp for this request.
1806
1807 Fcb - This is the Fcb for this data stream. It must be a data stream.
1808
1809 UserBuffer - Current position in the user's buffer.
1810
1811 UserBufferOffset - Offset of this buffer from the beginning of the user's
1812 buffer for the original request.
1813
1814 StartingOffset - Offset in the stream to begin the read.
1815
1816 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1817 to this point. We will stop early if we exceed the maximum number
1818 of parallel Ios we support.
1819
1820 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1821 this routine is called.
1822
1823 RunCount - Number of entries in the IoRuns array filled here.
1824
1825 ThisByteCount - Number of bytes described by the IoRun entries. Will
1826 not exceed the ByteCount passed in.
1827
1828 Return Value:
1829
1830 None
1831
1832 --*/
1833
1834 {
1835 PIO_RUN ThisIoRun = IoRuns;
1836 BOOLEAN PerformedCopy;
1837
1838 //
1839 // The following deal with where we are in the range of raw sectors.
1840 // Note that we will bias the input file offset by the RIFF header
1841 // to deal directly with the raw sectors.
1842 //
1843
1844 ULONG RawSectorOffset;
1845 ULONG RemainingRawByteCount = ByteCount;
1846 LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER );
1847
1848 //
1849 // The following is the offset into the cooked sectors for the file.
1850 //
1851
1852 LONGLONG CurrentCookedOffset;
1853 ULONG RemainingCookedByteCount;
1854
1855 //
1856 // Following indicate the state of the user's buffer. We have
1857 // the destination of the next transfer and its offset in the
1858 // buffer. We also have the next available position in the buffer
1859 // available for a scratch buffer.
1860 //
1861
1862 PVOID CurrentUserBuffer = UserBuffer;
1863 ULONG CurrentUserBufferOffset = UserBufferOffset;
1864
1865 //
1866 // The following is the next contiguous bytes on the disk to
1867 // transfer. These are represented by cooked byte offset and length.
1868 // We also compute the number of raw bytes in the current transfer.
1869 //
1870
1871 LONGLONG DiskOffset = 0;
1872 ULONG CurrentCookedByteCount = 0;
1873 ULONG CurrentRawByteCount;
1874
1875 PAGED_CODE();
1876
1877 //
1878 // We need to maintain our position as we walk through the sectors on the disk.
1879 // We keep separate values for the cooked offset as well as the raw offset.
1880 // These are initialized on sector boundaries and we move through these
1881 // the file sector-by-sector.
1882 //
1883 // Try to do 32-bit math.
1884 //
1885
1886 if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) {
1887
1888 //
1889 // Prefix/fast: Note that the following are safe since we only
1890 // take this path for 32bit offsets.
1891 //
1892
1893 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
1894
1895 #ifdef _MSC_VER
1896 #pragma prefast( suppress: __WARNING_RESULTOFSHIFTCASTTOLARGERSIZE, "This is fine beacuse raw sector size > sector shift" )
1897 #endif
1898 CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
1899
1900 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
1901
1902 //
1903 // Otherwise we need to do 64-bit math (sigh).
1904 //
1905
1906 } else {
1907
1908 CurrentRawOffset /= RAW_SECTOR_SIZE;
1909
1910 CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;
1911
1912 CurrentRawOffset *= RAW_SECTOR_SIZE;
1913 }
1914
1915 //
1916 // Now compute the full number of sectors to be read. Count all of the raw
1917 // sectors that need to be read and convert to cooked bytes.
1918 //
1919
1920 RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
1921 CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;
1922
1923 RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;
1924
1925 //
1926 // Initialize the RunCount and ByteCount.
1927 //
1928
1929 *RunCount = 0;
1930 *ThisByteCount = 0;
1931
1932 //
1933 // Loop while there are more bytes to process or there are
1934 // available entries in the IoRun array.
1935 //
1936
1937 while (TRUE) {
1938
1939 PerformedCopy = FALSE;
1940 *RunCount += 1;
1941
1942 //
1943 // Initialize the current position in the IoRuns array. Find the
1944 // eventual destination in the user's buffer for this portion of the transfer.
1945 //
1946
1947 ThisIoRun->UserBuffer = CurrentUserBuffer;
1948
1949 //
1950 // Find the allocation information for the current offset in the
1951 // stream.
1952 //
1953
1954 CdLookupAllocation( IrpContext,
1955 Fcb,
1956 CurrentCookedOffset,
1957 &DiskOffset,
1958 &CurrentCookedByteCount );
1959 //
1960 // Maybe we got lucky and this is the same sector as in the
1961 // Vcb.
1962 //
1963
1964 if (DiskOffset == Fcb->Vcb->XADiskOffset) {
1965
1966 //
1967 // We will perform safe synchronization. Check again that
1968 // this is the correct sector.
1969 //
1970
1971 CdLockVcb( IrpContext, Fcb->Vcb );
1972
1973 if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
1974 (Fcb->Vcb->XASector != NULL)) {
1975
1976 //
1977 // Copy any bytes we can from the current sector.
1978 //
1979
1980 CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
1981
1982 //
1983 // Check whether we don't go to the end of the sector.
1984 //
1985
1986 if (CurrentRawByteCount > RemainingRawByteCount) {
1987
1988 CurrentRawByteCount = RemainingRawByteCount;
1989 }
1990
1991 RtlCopyMemory( CurrentUserBuffer,
1992 Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
1993 CurrentRawByteCount );
1994
1995 CdUnlockVcb( IrpContext, Fcb->Vcb );
1996
1997 //
1998 // Adjust the run count and pointer in the IoRuns array
1999 // to show that we didn't use a position.
2000 //
2001
2002 *RunCount -= 1;
2003 ThisIoRun -= 1;
2004
2005 //
2006 // Remember that we performed a copy operation.
2007 //
2008
2009 PerformedCopy = TRUE;
2010
2011 CurrentCookedByteCount = SECTOR_SIZE;
2012
2013 } else {
2014
2015 //
2016 // The safe test showed no available buffer. Drop down to common code to
2017 // perform the Io.
2018 //
2019
2020 CdUnlockVcb( IrpContext, Fcb->Vcb );
2021 }
2022 }
2023
2024 //
2025 // No work in this pass if we did a copy operation.
2026 //
2027
2028 if (!PerformedCopy) {
2029
2030 //
2031 // Limit ourselves by the number of remaining cooked bytes.
2032 //
2033
2034 if (CurrentCookedByteCount > RemainingCookedByteCount) {
2035
2036 CurrentCookedByteCount = RemainingCookedByteCount;
2037 }
2038
2039 ThisIoRun->DiskOffset = DiskOffset;
2040 ThisIoRun->TransferBufferOffset = RawSectorOffset;
2041
2042 //
2043 // We will always need to perform copy operations for XA files.
2044 // We allocate an auxillary buffer to read the start of the
2045 // transfer. Then we can use a range of the user's buffer to
2046 // perform the next range of the transfer. Finally we may
2047 // need to allocate a buffer for the tail of the transfer.
2048 //
2049 // We can use the user's buffer (at the current scratch buffer) if the
2050 // following are true:
2051 //
2052 // If we are to store the beginning of the raw sector in the user's buffer.
2053 // The current scratch buffer precedes the destination in the user's buffer
2054 // (and hence also lies within it)
2055 // There are enough bytes remaining in the buffer for at least one
2056 // raw sector.
2057 //
2058
2059 if ((RawSectorOffset == 0) &&
2060 (RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
2061
2062 //
2063 // We can use the scratch buffer. We must ensure we don't send down reads
2064 // greater than the device can handle, since the driver is unable to split
2065 // raw requests.
2066 //
2067
2068 if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {
2069
2070 CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
2071
2072 } else {
2073
2074 CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
2075 CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
2076 }
2077
2078 //
2079 // Now make sure we are within the page transfer limit.
2080 //
2081
2082 while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
2083 Fcb->Vcb->MaximumPhysicalPages ) {
2084
2085 CurrentRawByteCount -= RAW_SECTOR_SIZE;
2086 CurrentCookedByteCount -= SECTOR_SIZE;
2087 }
2088
2089 //
2090 // Trim the number of bytes to read if it won't fit into the current buffer. Take
2091 // account of the fact that we must read in whole raw sector multiples.
2092 //
2093
2094 while (RawSectorAlign( CurrentRawByteCount) > RemainingRawByteCount) {
2095
2096 CurrentRawByteCount -= RAW_SECTOR_SIZE;
2097 CurrentCookedByteCount -= SECTOR_SIZE;
2098 }
2099
2100 //
2101 // Now trim the maximum number of raw bytes to the remaining bytes.
2102 //
2103
2104 if (CurrentRawByteCount > RemainingRawByteCount) {
2105
2106 CurrentRawByteCount = RemainingRawByteCount;
2107 }
2108
2109 //
2110 // Update the IO run array. We point to the scratch buffer as
2111 // well as the buffer and Mdl in the original Irp.
2112 //
2113
2114 ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
2115
2116 //
2117 // Point to the user's buffer and Mdl for this transfer.
2118 //
2119
2120 ThisIoRun->TransferBuffer = CurrentUserBuffer;
2121 ThisIoRun->TransferMdl = Irp->MdlAddress;
2122 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
2123 CurrentUserBufferOffset,
2124 PVOID);
2125
2126 } else {
2127
2128 //
2129 // We need to determine the number of bytes to transfer and the
2130 // offset into this page to begin the transfer.
2131 //
2132 // We will transfer only one raw sector.
2133 //
2134
2135 ThisIoRun->DiskByteCount = SECTOR_SIZE;
2136
2137 CurrentCookedByteCount = SECTOR_SIZE;
2138
2139 ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
2140 ThisIoRun->TransferBufferOffset = RawSectorOffset;
2141
2142 if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {
2143
2144 ThisIoRun->TransferByteCount = RemainingRawByteCount;
2145 }
2146
2147 CurrentRawByteCount = ThisIoRun->TransferByteCount;
2148
2149 //
2150 // We need to allocate an auxillary buffer. We will allocate
2151 // a single page. Then we will build an Mdl to describe the buffer.
2152 //
2153
2154 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
2155
2156 //
2157 // Allocate and build the Mdl to describe this buffer.
2158 //
2159
2160 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
2161 PAGE_SIZE,
2162 FALSE,
2163 FALSE,
2164 NULL );
2165
2166 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
2167
2168 if (ThisIoRun->TransferMdl == NULL) {
2169
2170 IrpContext->Irp->IoStatus.Information = 0;
2171 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2172 }
2173
2174 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
2175 }
2176 }
2177
2178 //
2179 // Update the byte count for our caller.
2180 //
2181
2182 RemainingRawByteCount -= CurrentRawByteCount;
2183 *ThisByteCount += CurrentRawByteCount;
2184
2185 //
2186 // Break out if no more positions in the IoRuns array or
2187 // we have all of the bytes accounted for.
2188 //
2189
2190 if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
2191
2192 break;
2193 }
2194
2195 //
2196 // Update our local pointers to allow for the current range of bytes.
2197 //
2198
2199 ThisIoRun += 1;
2200
2201 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID );
2202 CurrentUserBufferOffset += CurrentRawByteCount;
2203
2204 RawSectorOffset = 0;
2205
2206 CurrentCookedOffset += CurrentCookedByteCount;
2207 RemainingCookedByteCount -= CurrentCookedByteCount;
2208 }
2209
2210 return;
2211 }
2212
2213 \f
2214 //
2215 // Local support routine
2216 //
2217
2218 BOOLEAN
2219 CdFinishBuffers (
2220 _In_ PIRP_CONTEXT IrpContext,
2221 _Inout_ PIO_RUN IoRuns,
2222 _In_ ULONG RunCount,
2223 _In_ BOOLEAN FinalCleanup,
2224 _In_ BOOLEAN SaveXABuffer
2225 )
2226
2227 /*++
2228
2229 Routine Description:
2230
2231 This routine is called to perform any data transferred required for
2232 unaligned Io or to perform the final cleanup of the IoRuns array.
2233
2234 In all cases this is where we will deallocate any buffer and mdl
2235 allocated to perform the unaligned transfer. If this is not the
2236 final cleanup then we also transfer the bytes to the user buffer
2237 and flush the hardware cache.
2238
2239 We walk backwards through the run array because we may be shifting data
2240 in the user's buffer. Typical case is where we allocated a buffer for
2241 the first part of a read and then used the user's buffer for the
2242 next section (but stored it at the beginning of the buffer.
2243
2244 Arguments:
2245
2246 IoRuns - Pointer to the IoRuns array.
2247
2248 RunCount - Number of entries in the IoRuns array filled here.
2249
2250 FinalCleanup - Indicates if we should be deallocating temporary buffers
2251 (TRUE) or transferring bytes for a unaligned transfers and
2252 deallocating the buffers (FALSE). Flush the system cache if
2253 transferring data.
2254
2255 SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
2256
2257 Return Value:
2258
2259 BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
2260
2261 --*/
2262
2263 {
2264 BOOLEAN FlushIoBuffers = FALSE;
2265
2266 ULONG RemainingEntries = RunCount;
2267 PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
2268 PVCB Vcb;
2269
2270 PAGED_CODE();
2271
2272 //
2273 // Walk through each entry in the IoRun array.
2274 //
2275
2276 while (RemainingEntries != 0) {
2277
2278 //
2279 // We only need to deal with the case of an unaligned transfer.
2280 //
2281
2282 if (ThisIoRun->TransferByteCount != 0) {
2283
2284 //
2285 // If not the final cleanup then transfer the data to the
2286 // user's buffer and remember that we will need to flush
2287 // the user's buffer to memory.
2288 //
2289
2290 if (!FinalCleanup) {
2291
2292 RtlCopyMemory( ThisIoRun->UserBuffer,
2293 Add2Ptr( ThisIoRun->TransferBuffer,
2294 ThisIoRun->TransferBufferOffset,
2295 PVOID ),
2296 ThisIoRun->TransferByteCount );
2297
2298 FlushIoBuffers = TRUE;
2299 }
2300
2301 //
2302 // Free any Mdl we may have allocated. If the Mdl isn't
2303 // present then we must have failed during the allocation
2304 // phase.
2305 //
2306
2307 if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
2308
2309 if (ThisIoRun->TransferMdl != NULL) {
2310
2311 IoFreeMdl( ThisIoRun->TransferMdl );
2312 }
2313
2314 //
2315 // Now free any buffer we may have allocated. If the Mdl
2316 // doesn't match the original Mdl then free the buffer.
2317 //
2318
2319 if (ThisIoRun->TransferBuffer != NULL) {
2320
2321 //
2322 // If this is the final buffer for an XA read then store this buffer
2323 // into the Vcb so that we will have it when reading any remaining
2324 // portion of this buffer.
2325 //
2326
2327 if (SaveXABuffer) {
2328
2329 Vcb = IrpContext->Vcb;
2330
2331 CdLockVcb( IrpContext, Vcb );
2332
2333 if (Vcb->XASector != NULL) {
2334
2335 CdFreePool( &Vcb->XASector );
2336 }
2337
2338 Vcb->XASector = ThisIoRun->TransferBuffer;
2339 Vcb->XADiskOffset = ThisIoRun->DiskOffset;
2340
2341 SaveXABuffer = FALSE;
2342
2343 CdUnlockVcb( IrpContext, Vcb );
2344
2345 //
2346 // Otherwise just free the buffer.
2347 //
2348
2349 } else {
2350
2351 CdFreePool( &ThisIoRun->TransferBuffer );
2352 }
2353 }
2354 }
2355 }
2356
2357 //
2358 // Now handle the case where we failed in the process
2359 // of allocating associated Irps and Mdls.
2360 //
2361
2362 if (ThisIoRun->SavedIrp != NULL) {
2363
2364 if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
2365
2366 IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
2367 }
2368
2369 IoFreeIrp( ThisIoRun->SavedIrp );
2370 }
2371
2372 //
2373 // Move to the previous IoRun entry.
2374 //
2375
2376 ThisIoRun -= 1;
2377 RemainingEntries -= 1;
2378 }
2379
2380 //
2381 // If we copied any data then flush the Io buffers.
2382 //
2383
2384 return FlushIoBuffers;
2385 }
2386
2387 // Tell prefast this is a completion routine.
2388 IO_COMPLETION_ROUTINE CdSyncCompletionRoutine;
2389
2390 NTSTATUS
2391 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2392 CdSyncCompletionRoutine (
2393 PDEVICE_OBJECT DeviceObject,
2394 PIRP Irp,
2395 PVOID Contxt
2396 )
2397
2398 /*++
2399
2400 Routine Description:
2401
2402 Completion routine for synchronizing back to dispatch.
2403
2404 Arguments:
2405
2406 Contxt - pointer to KEVENT.
2407
2408 Return Value:
2409
2410 STATUS_MORE_PROCESSING_REQUIRED
2411
2412 --*/
2413
2414 {
2415 PKEVENT Event = (PKEVENT)Contxt;
2416 _Analysis_assume_(Contxt != NULL);
2417
2418 UNREFERENCED_PARAMETER( Irp );
2419 UNREFERENCED_PARAMETER( DeviceObject );
2420
2421 KeSetEvent( Event, 0, FALSE );
2422
2423 //
2424 // We don't want IO to get our IRP and free it.
2425 //
2426
2427 return STATUS_MORE_PROCESSING_REQUIRED;
2428 }
2429
2430
2431 _Requires_lock_held_(_Global_critical_region_)
2432 VOID
2433 CdFreeDirCache (
2434 _In_ PIRP_CONTEXT IrpContext
2435 )
2436
2437 /*++
2438
2439 Routine Description:
2440
2441 Safely frees the sector cache buffer.
2442
2443 Arguments:
2444
2445 Return Value:
2446
2447 None.
2448
2449 --*/
2450
2451 {
2452 PAGED_CODE();
2453
2454 if (NULL != IrpContext->Vcb->SectorCacheBuffer) {
2455
2456 CdAcquireCacheForUpdate( IrpContext);
2457 CdFreePool( &IrpContext->Vcb->SectorCacheBuffer);
2458 CdReleaseCache( IrpContext);
2459 }
2460 }
2461
2462 _Requires_lock_held_(_Global_critical_region_)
2463 BOOLEAN
2464 CdReadDirDataThroughCache (
2465 _In_ PIRP_CONTEXT IrpContext,
2466 _In_ PIO_RUN Run
2467 )
2468
2469 /*++
2470
2471 Routine Description:
2472
2473 Reads blocks through the sector cache. If the data is present, then it
2474 is copied from memory. If not present, one of the cache chunks will be
2475 replaced with a chunk containing the requested region, and the data
2476 copied from there.
2477
2478 Only intended for reading *directory* blocks, for the purpose of pre-caching
2479 directory information, by reading a chunk of blocks which hopefully contains
2480 other directory blocks, rather than just the (usually) single block requested.
2481
2482 Arguments:
2483
2484 Run - description of extent required, and buffer to read into.
2485
2486 Return Value:
2487
2488 None. Raises on error.
2489
2490 --*/
2491
2492 {
2493 PVCB Vcb = IrpContext->Vcb;
2494 ULONG Lbn = SectorsFromLlBytes( Run->DiskOffset);
2495 ULONG Remaining = SectorsFromBytes( Run->DiskByteCount);
2496 PUCHAR UserBuffer = Run->TransferBuffer;
2497
2498 NTSTATUS Status;
2499 ULONG Found;
2500 ULONG BufferSectorOffset;
2501 ULONG StartBlock;
2502 ULONG EndBlock;
2503 ULONG Blocks;
2504
2505 PIO_STACK_LOCATION IrpSp;
2506 IO_STATUS_BLOCK Iosb;
2507
2508 PTRACK_DATA TrackData;
2509
2510 #if DBG
2511 BOOLEAN JustRead = FALSE;
2512 #endif
2513
2514 ULONG Index;
2515 PCD_SECTOR_CACHE_CHUNK Buffer;
2516 BOOLEAN Result = FALSE;
2517
2518 PAGED_CODE();
2519
2520 CdAcquireCacheForRead( IrpContext);
2521
2522 _SEH2_TRY {
2523
2524 //
2525 // Check the cache hasn't gone away due to volume verify failure (which
2526 // is the *only* reason it'll go away). If this is the case we raise
2527 // the same error any I/O would return if the cache weren't here.
2528 //
2529
2530 if (NULL == Vcb->SectorCacheBuffer) {
2531
2532 CdRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED);
2533 }
2534
2535 while (Remaining) {
2536
2537 Buffer = NULL;
2538
2539 //
2540 // Look to see if any portion is currently cached.
2541 //
2542
2543 for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) {
2544
2545 if ((Vcb->SecCacheChunks[ Index].BaseLbn != -1) &&
2546 (Vcb->SecCacheChunks[ Index].BaseLbn <= Lbn) &&
2547 ((Vcb->SecCacheChunks[ Index].BaseLbn + CD_SEC_CHUNK_BLOCKS) > Lbn)) {
2548
2549 Buffer = &Vcb->SecCacheChunks[ Index];
2550 break;
2551 }
2552 }
2553
2554 //
2555 // If we found any, copy it out and continue.
2556 //
2557
2558 if (NULL != Buffer) {
2559
2560 BufferSectorOffset = Lbn - Buffer->BaseLbn;
2561 Found = Min( CD_SEC_CHUNK_BLOCKS - BufferSectorOffset, Remaining);
2562
2563 RtlCopyMemory( UserBuffer,
2564 Buffer->Buffer + BytesFromSectors( BufferSectorOffset),
2565 BytesFromSectors( Found));
2566
2567 Remaining -= Found;
2568 UserBuffer += BytesFromSectors( Found);
2569 Lbn += Found;
2570 #if DBG
2571 //
2572 // Update stats. Don't count a hit if we've just read the data in.
2573 //
2574
2575 if (!JustRead) {
2576
2577 InterlockedIncrement( (LONG*)&Vcb->SecCacheHits);
2578 }
2579
2580 JustRead = FALSE;
2581 #endif
2582 continue;
2583 }
2584
2585 //
2586 // Missed the cache, so we need to read a new chunk. Take the cache
2587 // resource exclusive while we do so.
2588 //
2589
2590 CdReleaseCache( IrpContext);
2591 CdAcquireCacheForUpdate( IrpContext);
2592 #if DBG
2593 Vcb->SecCacheMisses += 1;
2594 #endif
2595 //
2596 // Select the chunk to replace and calculate the start block of the
2597 // chunk to cache. We cache blocks which start on Lbns aligned on
2598 // multiples of chunk size, treating block 16 (VRS start) as block
2599 // zero.
2600 //
2601
2602 Buffer = &Vcb->SecCacheChunks[ Vcb->SecCacheLRUChunkIndex];
2603
2604 StartBlock = Lbn - ((Lbn - 16) % CD_SEC_CHUNK_BLOCKS);
2605
2606 //
2607 // Make sure we don't try and read past end of the last track.
2608 //
2609
2610 TrackData = &Vcb->CdromToc->TrackData[(Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack + 1)];
2611
2612 SwapCopyUchar4( &EndBlock, &TrackData->Address );
2613
2614 Blocks = EndBlock - StartBlock;
2615
2616 if (Blocks > CD_SEC_CHUNK_BLOCKS) {
2617
2618 Blocks = CD_SEC_CHUNK_BLOCKS;
2619 }
2620
2621 if ((0 == Blocks) || (Lbn < 16)) {
2622
2623 CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER);
2624 }
2625
2626 //
2627 // Now build / send the read request.
2628 //
2629
2630 IoReuseIrp( Vcb->SectorCacheIrp, STATUS_SUCCESS);
2631
2632 KeClearEvent( &Vcb->SectorCacheEvent);
2633 Vcb->SectorCacheIrp->Tail.Overlay.Thread = PsGetCurrentThread();
2634
2635 //
2636 // Get a pointer to the stack location of the first driver which will be
2637 // invoked. This is where the function codes and the parameters are set.
2638 //
2639
2640 IrpSp = IoGetNextIrpStackLocation( Vcb->SectorCacheIrp);
2641 IrpSp->MajorFunction = (UCHAR) IRP_MJ_READ;
2642
2643 //
2644 // Build an MDL to describe the buffer.
2645 //
2646
2647 IoAllocateMdl( Buffer->Buffer,
2648 BytesFromSectors( Blocks),
2649 FALSE,
2650 FALSE,
2651 Vcb->SectorCacheIrp);
2652
2653 if (NULL == Vcb->SectorCacheIrp->MdlAddress) {
2654
2655 IrpContext->Irp->IoStatus.Information = 0;
2656 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES);
2657 }
2658
2659 //
2660 // We're reading/writing into the block cache (paged pool). Lock the
2661 // pages and update the MDL with physical page information.
2662 //
2663
2664 _SEH2_TRY {
2665
2666 MmProbeAndLockPages( Vcb->SectorCacheIrp->MdlAddress,
2667 KernelMode,
2668 (LOCK_OPERATION) IoWriteAccess );
2669 }
2670 #ifdef _MSC_VER
2671 #pragma warning(suppress: 6320)
2672 #endif
2673 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2674
2675 IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress );
2676 Vcb->SectorCacheIrp->MdlAddress = NULL;
2677 } _SEH2_END;
2678
2679 if (NULL == Vcb->SectorCacheIrp->MdlAddress) {
2680
2681 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2682 }
2683
2684 //
2685 // Reset the BaseLbn as we can't trust this Buffer's data until the request
2686 // is successfully completed.
2687 //
2688
2689 Buffer->BaseLbn = (ULONG)-1;
2690
2691 IrpSp->Parameters.Read.Length = BytesFromSectors( Blocks);
2692 IrpSp->Parameters.Read.ByteOffset.QuadPart = LlBytesFromSectors( StartBlock);
2693
2694 IoSetCompletionRoutine( Vcb->SectorCacheIrp,
2695 CdSyncCompletionRoutine,
2696 &Vcb->SectorCacheEvent,
2697 TRUE,
2698 TRUE,
2699 TRUE );
2700
2701 Vcb->SectorCacheIrp->UserIosb = &Iosb;
2702
2703 Status = IoCallDriver( Vcb->TargetDeviceObject, Vcb->SectorCacheIrp );
2704
2705 if (STATUS_PENDING == Status) {
2706
2707
2708 (VOID)KeWaitForSingleObject( &Vcb->SectorCacheEvent,
2709 Executive,
2710 KernelMode,
2711 FALSE,
2712 NULL );
2713
2714 Status = Vcb->SectorCacheIrp->IoStatus.Status;
2715 }
2716
2717 Vcb->SectorCacheIrp->UserIosb = NULL;
2718
2719 //
2720 // Unlock the pages and free the MDL.
2721 //
2722
2723 MmUnlockPages( Vcb->SectorCacheIrp->MdlAddress );
2724 IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress );
2725 Vcb->SectorCacheIrp->MdlAddress = NULL;
2726
2727 if (!NT_SUCCESS( Status )) {
2728
2729 try_leave( Status );
2730 }
2731
2732 //
2733 // Update the buffer information, and drop the cache resource to shared
2734 // to allow in reads.
2735 //
2736
2737 Buffer->BaseLbn = StartBlock;
2738 Vcb->SecCacheLRUChunkIndex = (Vcb->SecCacheLRUChunkIndex + 1) % CD_SEC_CACHE_CHUNKS;
2739
2740 CdConvertCacheToShared( IrpContext);
2741 #if DBG
2742 JustRead = TRUE;
2743 #endif
2744 }
2745
2746 Result = TRUE;
2747 }
2748 _SEH2_FINALLY {
2749
2750 CdReleaseCache( IrpContext);
2751 } _SEH2_END;
2752
2753 return Result;
2754 }
2755
2756
2757 //
2758 // Local support routine
2759 //
2760
2761 _Requires_lock_held_(_Global_critical_region_)
2762 VOID
2763 CdMultipleAsync (
2764 _In_ PIRP_CONTEXT IrpContext,
2765 _In_ PFCB Fcb,
2766 _In_ ULONG RunCount,
2767 _Inout_ PIO_RUN IoRuns
2768 )
2769
2770 /*++
2771
2772 Routine Description:
2773
2774 This routine first does the initial setup required of a Master IRP that is
2775 going to be completed using associated IRPs. This routine should not
2776 be used if only one async request is needed, instead the single read
2777 async routines should be called.
2778
2779 A context parameter is initialized, to serve as a communications area
2780 between here and the common completion routine.
2781
2782 Next this routine reads or writes one or more contiguous sectors from
2783 a device asynchronously, and is used if there are multiple reads for a
2784 master IRP. A completion routine is used to synchronize with the
2785 completion of all of the I/O requests started by calls to this routine.
2786
2787 Also, prior to calling this routine the caller must initialize the
2788 IoStatus field in the Context, with the correct success status and byte
2789 count which are expected if all of the parallel transfers complete
2790 successfully. After return this status will be unchanged if all requests
2791 were, in fact, successful. However, if one or more errors occur, the
2792 IoStatus will be modified to reflect the error status and byte count
2793 from the first run (by Vbo) which encountered an error. I/O status
2794 from all subsequent runs will not be indicated.
2795
2796 Arguments:
2797
2798 RunCount - Supplies the number of multiple async requests
2799 that will be issued against the master irp.
2800
2801 IoRuns - Supplies an array containing the Offset and ByteCount for the
2802 separate requests.
2803
2804 Return Value:
2805
2806 None.
2807
2808 --*/
2809
2810 {
2811 PIO_COMPLETION_ROUTINE CompletionRoutine;
2812 PIO_STACK_LOCATION IrpSp;
2813 PMDL Mdl;
2814 PIRP Irp;
2815 PIRP MasterIrp;
2816 ULONG UnwindRunCount;
2817 BOOLEAN UseSectorCache;
2818
2819 PAGED_CODE();
2820
2821 //
2822 // Set up things according to whether this is truely async.
2823 //
2824
2825 CompletionRoutine = CdMultiSyncCompletionRoutine;
2826
2827 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
2828
2829 CompletionRoutine = CdMultiAsyncCompletionRoutine;
2830 }
2831
2832 //
2833 // For directories, use the sector cache.
2834 //
2835
2836 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
2837 (NULL != Fcb->Vcb->SectorCacheBuffer) &&
2838 (VcbMounted == IrpContext->Vcb->VcbCondition)) {
2839
2840 UseSectorCache = TRUE;
2841 }
2842 else {
2843
2844 UseSectorCache = FALSE;
2845 }
2846
2847 //
2848 // Initialize some local variables.
2849 //
2850
2851 MasterIrp = IrpContext->Irp;
2852
2853 //
2854 // Itterate through the runs, doing everything that can fail.
2855 // We let the cleanup in CdFinishBuffers clean up on error.
2856 //
2857
2858 for (UnwindRunCount = 0;
2859 UnwindRunCount < RunCount;
2860 UnwindRunCount += 1) {
2861
2862 if (UseSectorCache) {
2863
2864 if (!CdReadDirDataThroughCache( IrpContext, &IoRuns[ UnwindRunCount])) {
2865
2866 //
2867 // Turn off using directory cache and restart all over again.
2868 //
2869
2870 UseSectorCache = FALSE;
2871 UnwindRunCount = 0;
2872 }
2873
2874 continue;
2875 }
2876
2877 //
2878 // Create an associated IRP, making sure there is one stack entry for
2879 // us, as well.
2880 //
2881
2882 IoRuns[UnwindRunCount].SavedIrp =
2883 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
2884
2885 if (Irp == NULL) {
2886
2887 IrpContext->Irp->IoStatus.Information = 0;
2888 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2889 }
2890
2891 //
2892 // Allocate and build a partial Mdl for the request.
2893 //
2894
2895 Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
2896 IoRuns[UnwindRunCount].DiskByteCount,
2897 FALSE,
2898 FALSE,
2899 Irp );
2900
2901 if (Mdl == NULL) {
2902
2903 IrpContext->Irp->IoStatus.Information = 0;
2904 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2905 }
2906
2907 IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
2908 Mdl,
2909 IoRuns[UnwindRunCount].TransferVirtualAddress,
2910 IoRuns[UnwindRunCount].DiskByteCount );
2911
2912 //
2913 // Get the first IRP stack location in the associated Irp
2914 //
2915
2916 IoSetNextIrpStackLocation( Irp );
2917 IrpSp = IoGetCurrentIrpStackLocation( Irp );
2918
2919 //
2920 // Setup the Stack location to describe our read.
2921 //
2922
2923 IrpSp->MajorFunction = IRP_MJ_READ;
2924 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
2925 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
2926
2927 //
2928 // Set up the completion routine address in our stack frame.
2929 //
2930
2931 IoSetCompletionRoutine( Irp,
2932 CompletionRoutine,
2933 IrpContext->IoContext,
2934 TRUE,
2935 TRUE,
2936 TRUE );
2937
2938 //
2939 // Setup the next IRP stack location in the associated Irp for the disk
2940 // driver beneath us.
2941 //
2942
2943 IrpSp = IoGetNextIrpStackLocation( Irp );
2944
2945 //
2946 // Setup the Stack location to do a read from the disk driver.
2947 //
2948
2949 IrpSp->MajorFunction = IRP_MJ_READ;
2950 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
2951 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
2952 }
2953
2954 //
2955 // If we used the cache, we're done.
2956 //
2957
2958 if (UseSectorCache) {
2959
2960 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
2961
2962 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
2963 KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE );
2964 }
2965
2966 return;
2967 }
2968
2969 //
2970 // We only need to set the associated IRP count in the master irp to
2971 // make it a master IRP. But we set the count to one more than our
2972 // caller requested, because we do not want the I/O system to complete
2973 // the I/O. We also set our own count.
2974 //
2975
2976 IrpContext->IoContext->IrpCount = RunCount;
2977 IrpContext->IoContext->MasterIrp = MasterIrp;
2978
2979 //
2980 // We set the count in the master Irp to 1 since typically we
2981 // will clean up the associated irps ourselves. Setting this to one
2982 // means completing the last associated Irp with SUCCESS (in the async
2983 // case) will complete the master irp.
2984 //
2985
2986 MasterIrp->AssociatedIrp.IrpCount = 1;
2987
2988 //
2989 // If we (FS) acquired locks, transition the lock owners to an object, since
2990 // when we return this thread could go away before request completion, and
2991 // the resource package may otherwise try to boost priority, etc.
2992 //
2993
2994 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ) &&
2995 FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
2996
2997 NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() );
2998
2999 IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3;
3000
3001 ExSetResourceOwnerPointer( IrpContext->IoContext->Resource,
3002 (PVOID)IrpContext->IoContext->ResourceThreadId );
3003 }
3004
3005 //
3006 // Now that all the dangerous work is done, issue the Io requests
3007 //
3008
3009 for (UnwindRunCount = 0;
3010 UnwindRunCount < RunCount;
3011 UnwindRunCount++) {
3012
3013 Irp = IoRuns[UnwindRunCount].SavedIrp;
3014 IoRuns[UnwindRunCount].SavedIrp = NULL;
3015
3016 if (NULL != Irp) {
3017
3018 //
3019 // If IoCallDriver returns an error, it has completed the Irp
3020 // and the error will be caught by our completion routines
3021 // and dealt with as a normal IO error.
3022 //
3023
3024 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
3025 }
3026 }
3027 }
3028
3029 \f
3030 //
3031 // Local support routine
3032 //
3033
3034 VOID
3035 CdMultipleXAAsync (
3036 _In_ PIRP_CONTEXT IrpContext,
3037 _In_ ULONG RunCount,
3038 _Inout_ PIO_RUN IoRuns,
3039 _In_ PRAW_READ_INFO RawReads,
3040 _In_ TRACK_MODE_TYPE TrackMode
3041 )
3042
3043 /*++
3044
3045 Routine Description:
3046
3047 This routine first does the initial setup required of a Master IRP that is
3048 going to be completed using associated IRPs. This routine is used to generate
3049 the associated Irps used to read raw sectors from the disk.
3050
3051 A context parameter is initialized, to serve as a communications area
3052 between here and the common completion routine.
3053
3054 Next this routine reads or writes one or more contiguous sectors from
3055 a device asynchronously, and is used if there are multiple reads for a
3056 master IRP. A completion routine is used to synchronize with the
3057 completion of all of the I/O requests started by calls to this routine.
3058
3059 Also, prior to calling this routine the caller must initialize the
3060 IoStatus field in the Context, with the correct success status and byte
3061 count which are expected if all of the parallel transfers complete
3062 successfully. After return this status will be unchanged if all requests
3063 were, in fact, successful. However, if one or more errors occur, the
3064 IoStatus will be modified to reflect the error status and byte count
3065 from the first run (by Vbo) which encountered an error. I/O status
3066 from all subsequent runs will not be indicated.
3067
3068 Arguments:
3069
3070 RunCount - Supplies the number of multiple async requests
3071 that will be issued against the master irp.
3072
3073 IoRuns - Supplies an array containing the Offset and ByteCount for the
3074 separate requests.
3075
3076 RawReads - Supplies an array of structures to store in the Irps passed to the
3077 device driver to perform the low-level Io.
3078
3079 TrackMode - Supplies the recording mode of sectors in these IoRuns
3080
3081 Return Value:
3082
3083 None.
3084
3085 --*/
3086
3087 {
3088 PIO_STACK_LOCATION IrpSp;
3089 PMDL Mdl;
3090 PIRP Irp;
3091 PIRP MasterIrp;
3092 ULONG UnwindRunCount;
3093 ULONG RawByteCount;
3094
3095 PIO_RUN ThisIoRun = IoRuns;
3096 PRAW_READ_INFO ThisRawRead = RawReads;
3097
3098 PAGED_CODE();
3099
3100 //
3101 // Initialize some local variables.
3102 //
3103
3104 MasterIrp = IrpContext->Irp;
3105
3106 //
3107 // Itterate through the runs, doing everything that can fail.
3108 // We let the cleanup in CdFinishBuffers clean up on error.
3109 //
3110
3111 for (UnwindRunCount = 0;
3112 UnwindRunCount < RunCount;
3113 UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) {
3114
3115 //
3116 // Create an associated IRP, making sure there is one stack entry for
3117 // us, as well.
3118 //
3119
3120 ThisIoRun->SavedIrp =
3121 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
3122
3123 if (Irp == NULL) {
3124
3125 IrpContext->Irp->IoStatus.Information = 0;
3126 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
3127 }
3128
3129 //
3130 // Should have been passed a byte count of at least one sector, and
3131 // must be a multiple of sector size
3132 //
3133
3134 NT_ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
3135
3136 RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
3137
3138 //
3139 // Allocate and build a partial Mdl for the request.
3140 //
3141
3142 Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress,
3143 RawByteCount,
3144 FALSE,
3145 FALSE,
3146 Irp );
3147
3148 if (Mdl == NULL) {
3149
3150 IrpContext->Irp->IoStatus.Information = 0;
3151 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
3152 }
3153
3154 IoBuildPartialMdl( ThisIoRun->TransferMdl,
3155 Mdl,
3156 ThisIoRun->TransferVirtualAddress,
3157 RawByteCount);
3158 //
3159 // Get the first IRP stack location in the associated Irp
3160 //
3161
3162 IoSetNextIrpStackLocation( Irp );
3163 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3164
3165 //
3166 // Setup the Stack location to describe our read (using cooked values)
3167 // These values won't be used for the raw read in any case.
3168 //
3169
3170 IrpSp->MajorFunction = IRP_MJ_READ;
3171 IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount;
3172 IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset;
3173
3174 //
3175 // Set up the completion routine address in our stack frame.
3176 //
3177
3178 IoSetCompletionRoutine( Irp,
3179 CdMultiSyncCompletionRoutine,
3180 IrpContext->IoContext,
3181 TRUE,
3182 TRUE,
3183 TRUE );
3184
3185 //
3186 // Setup the next IRP stack location in the associated Irp for the disk
3187 // driver beneath us.
3188 //
3189
3190 IrpSp = IoGetNextIrpStackLocation( Irp );
3191
3192 //
3193 // Setup the stack location to do a read of raw sectors at this location.
3194 // Note that the storage stack always reads multiples of whole XA sectors.
3195 //
3196
3197 ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset;
3198 ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT;
3199 ThisRawRead->TrackMode = TrackMode;
3200
3201 IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
3202
3203 IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE;
3204 Irp->UserBuffer = ThisIoRun->TransferVirtualAddress;
3205
3206 IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO );
3207 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead;
3208
3209 IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ;
3210 }
3211
3212 //
3213 // We only need to set the associated IRP count in the master irp to
3214 // make it a master IRP. But we set the count to one more than our
3215 // caller requested, because we do not want the I/O system to complete
3216 // the I/O. We also set our own count.
3217 //
3218
3219 IrpContext->IoContext->IrpCount = RunCount;
3220 IrpContext->IoContext->MasterIrp = MasterIrp;
3221
3222 //
3223 // We set the count in the master Irp to 1 since typically we
3224 // will clean up the associated irps ourselves. Setting this to one
3225 // means completing the last associated Irp with SUCCESS (in the async
3226 // case) will complete the master irp.
3227 //
3228
3229 MasterIrp->AssociatedIrp.IrpCount = 1;
3230
3231 //
3232 // Now that all the dangerous work is done, issue the Io requests
3233 //
3234
3235 for (UnwindRunCount = 0;
3236 UnwindRunCount < RunCount;
3237 UnwindRunCount++) {
3238
3239 Irp = IoRuns[UnwindRunCount].SavedIrp;
3240 IoRuns[UnwindRunCount].SavedIrp = NULL;
3241
3242 //
3243 //
3244 // If IoCallDriver returns an error, it has completed the Irp
3245 // and the error will be caught by our completion routines
3246 // and dealt with as a normal IO error.
3247 //
3248
3249 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
3250 }
3251
3252 return;
3253 }
3254
3255 \f
3256 //
3257 // Local support routine
3258 //
3259
3260 _Requires_lock_held_(_Global_critical_region_)
3261 VOID
3262 CdSingleAsync (
3263 _In_ PIRP_CONTEXT IrpContext,
3264 _In_ PIO_RUN Run,
3265 _In_ PFCB Fcb
3266 )
3267
3268 /*++
3269
3270 Routine Description:
3271
3272 This routine reads one or more contiguous sectors from a device
3273 asynchronously, and is used if there is only one read necessary to
3274 complete the IRP. It implements the read by simply filling
3275 in the next stack frame in the Irp, and passing it on. The transfer
3276 occurs to the single buffer originally specified in the user request.
3277
3278 Arguments:
3279
3280 ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
3281
3282 ByteCount - Supplies the number of bytes to read from the device
3283
3284 Return Value:
3285
3286 None.
3287
3288 --*/
3289
3290 {
3291 PIO_STACK_LOCATION IrpSp;
3292 PIO_COMPLETION_ROUTINE CompletionRoutine;
3293
3294 PAGED_CODE();
3295
3296 //
3297 // For directories, look in the sector cache,
3298 //
3299
3300 if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
3301 (NULL != Fcb->Vcb->SectorCacheBuffer) &&
3302 (VcbMounted == IrpContext->Vcb->VcbCondition)) {
3303
3304 if (CdReadDirDataThroughCache( IrpContext, Run )) {
3305
3306 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
3307
3308 IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
3309 KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE );
3310 }
3311
3312 return;
3313 }
3314 }
3315
3316 //
3317 // Set up things according to whether this is truely async.
3318 //
3319
3320 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
3321
3322 CompletionRoutine = CdSingleSyncCompletionRoutine;
3323
3324 } else {
3325
3326 CompletionRoutine = CdSingleAsyncCompletionRoutine;
3327
3328 //
3329 // If we (FS) acquired locks, transition the lock owners to an object, since
3330 // when we return this thread could go away before request completion, and
3331 // the resource package may otherwise try to boost priority, etc.
3332 //
3333
3334 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
3335
3336 NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() );
3337
3338 IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3;
3339
3340 ExSetResourceOwnerPointer( IrpContext->IoContext->Resource,
3341 (PVOID)IrpContext->IoContext->ResourceThreadId );
3342 }
3343 }
3344
3345 //
3346 // Set up the completion routine address in our stack frame.
3347 //
3348
3349 IoSetCompletionRoutine( IrpContext->Irp,
3350 CompletionRoutine,
3351 IrpContext->IoContext,
3352 TRUE,
3353 TRUE,
3354 TRUE );
3355
3356 //
3357 // Setup the next IRP stack location in the associated Irp for the disk
3358 // driver beneath us.
3359 //
3360
3361 IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp );
3362
3363 //
3364 // Setup the Stack location to do a read from the disk driver.
3365 //
3366
3367 IrpSp->MajorFunction = IrpContext->MajorFunction;
3368 IrpSp->Parameters.Read.Length = Run->DiskByteCount;
3369 IrpSp->Parameters.Read.ByteOffset.QuadPart = Run->DiskOffset;
3370
3371 //
3372 // Issue the Io request
3373 //
3374
3375 //
3376 // If IoCallDriver returns an error, it has completed the Irp
3377 // and the error will be caught by our completion routines
3378 // and dealt with as a normal IO error.
3379 //
3380
3381 (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
3382 }
3383
3384 \f
3385 //
3386 // Local support routine
3387 //
3388
3389 VOID
3390 CdWaitSync (
3391 _In_ PIRP_CONTEXT IrpContext
3392 )
3393
3394 /*++
3395
3396 Routine Description:
3397
3398 This routine waits for one or more previously started I/O requests
3399 from the above routines, by simply waiting on the event.
3400
3401 Arguments:
3402
3403 Return Value:
3404
3405 None
3406
3407 --*/
3408
3409 {
3410 PAGED_CODE();
3411
3412
3413 (VOID)KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
3414 Executive,
3415 KernelMode,
3416 FALSE,
3417 NULL );
3418
3419 KeClearEvent( &IrpContext->IoContext->SyncEvent );
3420 }
3421
3422 \f
3423 //
3424 // Local support routine
3425 //
3426
3427 NTSTATUS
3428 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3429 CdMultiSyncCompletionRoutine (
3430 PDEVICE_OBJECT DeviceObject,
3431 PIRP Irp,
3432 PVOID Context
3433 )
3434
3435 /*++
3436
3437 Routine Description:
3438
3439 This is the completion routine for all synchronous reads
3440 started via CdMultipleAsynch.
3441
3442 The completion routine has has the following responsibilities:
3443
3444 If the individual request was completed with an error, then
3445 this completion routine must see if this is the first error
3446 and remember the error status in the Context.
3447
3448 If the IrpCount goes to 1, then it sets the event in the Context
3449 parameter to signal the caller that all of the asynch requests
3450 are done.
3451
3452 Arguments:
3453
3454 DeviceObject - Pointer to the file system device object.
3455
3456 Irp - Pointer to the associated Irp which is being completed. (This
3457 Irp will no longer be accessible after this routine returns.)
3458
3459 Context - The context parameter which was specified for all of
3460 the multiple asynch I/O requests for this MasterIrp.
3461
3462 Return Value:
3463
3464 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3465 immediately complete the Master Irp without being in a race condition
3466 with the IoCompleteRequest thread trying to decrement the IrpCount in
3467 the Master Irp.
3468
3469 --*/
3470
3471 {
3472 PCD_IO_CONTEXT IoContext = Context;
3473 _Analysis_assume_(Context != NULL);
3474
3475 AssertVerifyDeviceIrp( Irp );
3476
3477 //
3478 // If we got an error (or verify required), remember it in the Irp
3479 //
3480
3481 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3482
3483 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
3484 IoContext->MasterIrp->IoStatus.Information = 0;
3485 }
3486
3487 //
3488 // We must do this here since IoCompleteRequest won't get a chance
3489 // on this associated Irp.
3490 //
3491
3492 IoFreeMdl( Irp->MdlAddress );
3493 IoFreeIrp( Irp );
3494
3495 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
3496
3497 //
3498 // Update the Master Irp with any error status from the associated Irps.
3499 //
3500
3501 IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
3502 KeSetEvent( &IoContext->SyncEvent, 0, FALSE );
3503 }
3504
3505 UNREFERENCED_PARAMETER( DeviceObject );
3506
3507 return STATUS_MORE_PROCESSING_REQUIRED;
3508 }
3509
3510 \f
3511 //
3512 // Local support routine
3513 //
3514
3515 NTSTATUS
3516 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3517 CdMultiAsyncCompletionRoutine (
3518 PDEVICE_OBJECT DeviceObject,
3519 PIRP Irp,
3520 PVOID Context
3521 )
3522
3523 /*++
3524
3525 Routine Description:
3526
3527 This is the completion routine for all asynchronous reads
3528 started via CdMultipleAsynch.
3529
3530 The completion routine has has the following responsibilities:
3531
3532 If the individual request was completed with an error, then
3533 this completion routine must see if this is the first error
3534 and remember the error status in the Context.
3535
3536 Arguments:
3537
3538 DeviceObject - Pointer to the file system device object.
3539
3540 Irp - Pointer to the associated Irp which is being completed. (This
3541 Irp will no longer be accessible after this routine returns.)
3542
3543 Context - The context parameter which was specified for all of
3544 the multiple asynch I/O requests for this MasterIrp.
3545
3546 Return Value:
3547
3548 Currently always returns STATUS_SUCCESS.
3549
3550 --*/
3551
3552 {
3553 PCD_IO_CONTEXT IoContext = Context;
3554 _Analysis_assume_(Context != NULL);
3555 AssertVerifyDeviceIrp( Irp );
3556
3557 UNREFERENCED_PARAMETER( DeviceObject );
3558
3559 //
3560 // If we got an error (or verify required), remember it in the Irp
3561 //
3562
3563 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3564
3565 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
3566 }
3567
3568 //
3569 // Decrement IrpCount and see if it goes to zero.
3570 //
3571
3572 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
3573
3574 //
3575 // Mark the master Irp pending
3576 //
3577
3578 IoMarkIrpPending( IoContext->MasterIrp );
3579
3580 //
3581 // Update the Master Irp with any error status from the associated Irps.
3582 //
3583
3584 IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
3585
3586 //
3587 // Update the information field with the correct value.
3588 //
3589
3590 IoContext->MasterIrp->IoStatus.Information = 0;
3591
3592 if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) {
3593
3594 IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount;
3595 }
3596
3597 //
3598 // Now release the resource
3599 //
3600
3601 _Analysis_assume_lock_held_(*IoContext->Resource);
3602 ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId );
3603
3604 //
3605 // and finally, free the context record.
3606 //
3607
3608 CdFreeIoContext( IoContext );
3609
3610 //
3611 // Return success in this case.
3612 //
3613
3614 return STATUS_SUCCESS;
3615
3616 } else {
3617
3618 //
3619 // We need to cleanup the associated Irp and its Mdl.
3620 //
3621
3622 IoFreeMdl( Irp->MdlAddress );
3623 IoFreeIrp( Irp );
3624
3625 return STATUS_MORE_PROCESSING_REQUIRED;
3626 }
3627
3628 }
3629
3630 \f
3631 //
3632 // Local support routine
3633 //
3634
3635 NTSTATUS
3636 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3637 CdSingleSyncCompletionRoutine (
3638 PDEVICE_OBJECT DeviceObject,
3639 PIRP Irp,
3640 PVOID Context
3641 )
3642
3643 /*++
3644
3645 Routine Description:
3646
3647 This is the completion routine for all reads started via CdSingleAsynch.
3648
3649 The completion routine has has the following responsibilities:
3650
3651 It sets the event in the Context parameter to signal the caller
3652 that all of the asynch requests are done.
3653
3654 Arguments:
3655
3656 DeviceObject - Pointer to the file system device object.
3657
3658 Irp - Pointer to the Irp for this request. (This Irp will no longer
3659 be accessible after this routine returns.)
3660
3661 Context - The context parameter which was specified in the call to
3662 CdSingleAsynch.
3663
3664 Return Value:
3665
3666 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3667 immediately complete the Master Irp without being in a race condition
3668 with the IoCompleteRequest thread trying to decrement the IrpCount in
3669 the Master Irp.
3670
3671 --*/
3672
3673 {
3674 _Analysis_assume_(Context != NULL);
3675
3676 UNREFERENCED_PARAMETER( DeviceObject );
3677
3678 AssertVerifyDeviceIrp( Irp );
3679
3680 //
3681 // Store the correct information field into the Irp.
3682 //
3683
3684 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3685
3686 Irp->IoStatus.Information = 0;
3687 }
3688
3689 KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE );
3690
3691 return STATUS_MORE_PROCESSING_REQUIRED;
3692 }
3693
3694 \f
3695 //
3696 // Local support routine
3697 //
3698
3699 NTSTATUS
3700 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3701 CdSingleAsyncCompletionRoutine (
3702 PDEVICE_OBJECT DeviceObject,
3703 PIRP Irp,
3704 PVOID Context
3705 )
3706
3707 /*++
3708
3709 Routine Description:
3710
3711 This is the completion routine for all asynchronous reads
3712 started via CdSingleAsynch.
3713
3714 Arguments:
3715
3716 DeviceObject - Pointer to the file system device object.
3717
3718 Irp - Pointer to the Irp for this request. (This Irp will no longer
3719 be accessible after this routine returns.)
3720
3721 Context - The context parameter which was specified in the call to
3722 CdSingleAsynch.
3723
3724 Return Value:
3725
3726 Currently always returns STATUS_SUCCESS.
3727
3728 --*/
3729
3730 {
3731 PCD_IO_CONTEXT IoContext = Context;
3732
3733 UNREFERENCED_PARAMETER( DeviceObject );
3734
3735 _Analysis_assume_(IoContext != NULL);
3736 AssertVerifyDeviceIrp( Irp );
3737
3738 //
3739 // Update the information field with the correct value for bytes read.
3740 //
3741
3742 Irp->IoStatus.Information = 0;
3743
3744 if (NT_SUCCESS( Irp->IoStatus.Status )) {
3745
3746 Irp->IoStatus.Information = IoContext->RequestedByteCount;
3747 }
3748
3749 //
3750 // Mark the Irp pending
3751 //
3752
3753 IoMarkIrpPending( Irp );
3754
3755 //
3756 // Now release the resource
3757 //
3758
3759 _Analysis_assume_lock_held_(*IoContext->Resource);
3760 ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId );
3761
3762 //
3763 // and finally, free the context record.
3764 //
3765
3766 CdFreeIoContext( IoContext );
3767 return STATUS_SUCCESS;
3768
3769 }
3770
3771 \f
3772 //
3773 // Local support routine
3774 //
3775
3776 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT))))
3777 _When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE)))
3778 VOID
3779 CdReadAudioSystemFile (
3780 _In_ PIRP_CONTEXT IrpContext,
3781 _In_ PFCB Fcb,
3782 _In_ LONGLONG StartingOffset,
3783 _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount,
3784 _Out_writes_bytes_(ByteCount) PVOID SystemBuffer
3785 )
3786
3787 /*++
3788
3789 Routine Description:
3790
3791 This routine is called to read the pseudo root directory and path
3792 table for a music disk. We build the individual elements on the
3793 stack and copy into the cache buffer.
3794
3795 Arguments:
3796
3797 Fcb - Fcb representing the file to read.
3798
3799 StartingOffset - Logical offset in the file to read from.
3800
3801 ByteCount - Number of bytes to read.
3802
3803 SystemBuffer - Pointer to buffer to fill in. This will always be page
3804 aligned.
3805
3806 Return Value:
3807
3808 None.
3809
3810 --*/
3811
3812 {
3813 PRAW_PATH_ISO RawPath;
3814 PRAW_DIRENT RawDirent;
3815
3816 ULONG CurrentTrack;
3817 ULONG SectorOffset;
3818 ULONG EntryCount;
3819 UCHAR TrackOnes;
3820 UCHAR TrackTens;
3821 PTRACK_DATA ThisTrack;
3822
3823 LONGLONG CurrentOffset;
3824
3825 PVOID CurrentSector;
3826
3827 PSYSTEM_USE_XA SystemUse;
3828
3829 ULONG BytesToCopy;
3830
3831 UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12];
3832
3833 PAGED_CODE();
3834
3835 //
3836 // If this is the path table then we just need a single entry.
3837 //
3838
3839 if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) {
3840
3841 //
3842 // Sanity check that the offset is zero.
3843 //
3844
3845 NT_ASSERT( StartingOffset == 0 );
3846
3847 //
3848 // Store a pseudo path entry in our local buffer.
3849 //
3850
3851 RawPath = (PRAW_PATH_ISO) LocalBuffer;
3852
3853 RtlZeroMemory( RawPath, sizeof( LocalBuffer ));
3854
3855 RawPath->DirIdLen = 1;
3856 RawPath->ParentNum = 1;
3857 RawPath->DirId[0] = '\0';
3858
3859 //
3860 // Now copy to the user's buffer.
3861 //
3862
3863 BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2;
3864
3865 if (BytesToCopy > ByteCount) {
3866
3867 BytesToCopy = ByteCount;
3868 }
3869
3870 RtlCopyMemory( SystemBuffer,
3871 RawPath,
3872 BytesToCopy );
3873
3874 //
3875 // We need to deal with the multiple sector case for the root directory.
3876 //
3877
3878 } else {
3879
3880 //
3881 // Initialize the first track to return to our caller.
3882 //
3883
3884 CurrentTrack = 0;
3885
3886 //
3887 // If the offset is zero then store the entries for the self and parent
3888 // entries.
3889 //
3890
3891 if (StartingOffset == 0) {
3892
3893 RawDirent = SystemBuffer;
3894
3895 //
3896 // Clear all of the fields initially.
3897 //
3898
3899 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
3900
3901 //
3902 // Now fill in the interesting fields.
3903 //
3904
3905 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
3906 RawDirent->FileIdLen = 1;
3907 RawDirent->FileId[0] = '\0';
3908 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
3909
3910 //
3911 // Set the time stamp to be Jan 1, 1995
3912 //
3913
3914 RawDirent->RecordTime[0] = 95;
3915 RawDirent->RecordTime[1] = 1;
3916 RawDirent->RecordTime[2] = 1;
3917
3918 SectorOffset = RawDirent->DirLen;
3919
3920 RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT );
3921
3922 //
3923 // Clear all of the fields initially.
3924 //
3925
3926 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
3927
3928 //
3929 // Now fill in the interesting fields.
3930 //
3931
3932 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
3933 RawDirent->FileIdLen = 1;
3934 RawDirent->FileId[0] = '\1';
3935 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
3936
3937 //
3938 // Set the time stamp to be Jan 1, 1995
3939 //
3940
3941 RawDirent->RecordTime[0] = 95;
3942 RawDirent->RecordTime[1] = 1;
3943 RawDirent->RecordTime[2] = 1;
3944
3945 SectorOffset += RawDirent->DirLen;
3946 EntryCount = 2;
3947
3948 //
3949 // Otherwise compute the starting track to write to the buffer.
3950 //
3951
3952 } else {
3953
3954 //
3955 // Count the tracks in each preceding sector.
3956 //
3957
3958 CurrentOffset = 0;
3959
3960 do {
3961
3962 CurrentTrack += CdAudioDirentsPerSector;
3963 CurrentOffset += SECTOR_SIZE;
3964
3965 } while (CurrentOffset < StartingOffset);
3966
3967 //
3968 // Bias the track count to reflect the two default entries.
3969 //
3970
3971 CurrentTrack -= 2;
3972
3973 SectorOffset = 0;
3974 EntryCount = 0;
3975 }
3976
3977 //
3978 // We now know the first track to return as well as where we are in
3979 // the current sector. We will walk through sector by sector adding
3980 // the entries for the separate tracks in the TOC. We will zero
3981 // any sectors or partial sectors without data.
3982 //
3983
3984 CurrentSector = SystemBuffer;
3985 BytesToCopy = SECTOR_SIZE;
3986
3987 //
3988 // Loop for each sector.
3989 //
3990
3991 do {
3992
3993 //
3994 // Add entries until we reach our threshold for each sector.
3995 //
3996
3997 do {
3998
3999 //
4000 // If we are beyond the entries in the TOC then exit.
4001 //
4002
4003 if (CurrentTrack >= IrpContext->Vcb->TrackCount) {
4004
4005 break;
4006 }
4007
4008 ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack];
4009
4010 //
4011 // Point to the current position in the buffer.
4012 //
4013
4014 RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT );
4015
4016 //
4017 // Clear all of the fields initially.
4018 //
4019
4020 RtlZeroMemory( RawDirent, CdAudioDirentSize );
4021
4022 //
4023 // Now fill in the interesting fields.
4024 //
4025
4026 RawDirent->DirLen = (UCHAR) CdAudioDirentSize;
4027 RawDirent->FileIdLen = CdAudioFileNameLength;
4028
4029 RtlCopyMemory( RawDirent->FileId,
4030 CdAudioFileName,
4031 CdAudioFileNameLength );
4032
4033 //
4034 // Set the time stamp to be Jan 1, 1995 00:00
4035 //
4036
4037 RawDirent->RecordTime[0] = 95;
4038 RawDirent->RecordTime[1] = 1;
4039 RawDirent->RecordTime[2] = 1;
4040
4041 //
4042 // Put the track number into the file name.
4043 //
4044
4045 TrackTens = TrackOnes = ThisTrack->TrackNumber;
4046
4047 TrackOnes = (TrackOnes % 10) + '0';
4048
4049 TrackTens /= 10;
4050 TrackTens = (TrackTens % 10) + '0';
4051
4052 RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens;
4053 RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes;
4054
4055 SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA );
4056
4057 SystemUse->Attributes = SYSTEM_USE_XA_DA;
4058 SystemUse->Signature = SYSTEM_XA_SIGNATURE;
4059
4060 //
4061 // Store the track number as the file number.
4062 //
4063
4064 SystemUse->FileNumber = (UCHAR) CurrentTrack;
4065
4066 EntryCount += 1;
4067 SectorOffset += CdAudioDirentSize;
4068 CurrentTrack += 1;
4069
4070 } while (EntryCount < CdAudioDirentsPerSector);
4071
4072 //
4073 // Zero the remaining portion of this buffer.
4074 //
4075
4076 RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ),
4077 SECTOR_SIZE - SectorOffset );
4078
4079 //
4080 // Prepare for the next sector.
4081 //
4082
4083 EntryCount = 0;
4084 BytesToCopy += SECTOR_SIZE;
4085 SectorOffset = 0;
4086 CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID );
4087
4088 } while (BytesToCopy <= ByteCount);
4089 }
4090
4091 return;
4092 }
4093
4094
4095 NTSTATUS
4096 CdHijackIrpAndFlushDevice (
4097 _In_ PIRP_CONTEXT IrpContext,
4098 _Inout_ PIRP Irp,
4099 _In_ PDEVICE_OBJECT TargetDeviceObject
4100 )
4101
4102 /*++
4103
4104 Routine Description:
4105
4106 This routine is called when we need to send a flush to a device but
4107 we don't have a flush Irp. What this routine does is make a copy
4108 of its current Irp stack location, but changes the Irp Major code
4109 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
4110 the knees in the completion routine, fix it up and return to the
4111 user as if nothing had happened.
4112
4113 Arguments:
4114
4115 Irp - The Irp to hijack
4116
4117 TargetDeviceObject - The device to send the request to.
4118
4119 Return Value:
4120
4121 NTSTATUS - The Status from the flush in case anybody cares.
4122
4123 --*/
4124
4125 {
4126 KEVENT Event;
4127 NTSTATUS Status;
4128 PIO_STACK_LOCATION NextIrpSp;
4129
4130 PAGED_CODE();
4131
4132 UNREFERENCED_PARAMETER( IrpContext );
4133
4134 //
4135 // Get the next stack location, and copy over the stack location
4136 //
4137
4138 NextIrpSp = IoGetNextIrpStackLocation( Irp );
4139
4140 *NextIrpSp = *IoGetCurrentIrpStackLocation( Irp );
4141
4142 NextIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
4143 NextIrpSp->MinorFunction = 0;
4144
4145 //
4146 // Set up the completion routine
4147 //
4148
4149 KeInitializeEvent( &Event, NotificationEvent, FALSE );
4150
4151 IoSetCompletionRoutine( Irp,
4152 CdSyncCompletionRoutine,
4153 &Event,
4154 TRUE,
4155 TRUE,
4156 TRUE );
4157
4158 //
4159 // Send the request.
4160 //
4161
4162 Status = IoCallDriver( TargetDeviceObject, Irp );
4163
4164 if (Status == STATUS_PENDING) {
4165
4166 (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
4167
4168 Status = Irp->IoStatus.Status;
4169 }
4170
4171 //
4172 // If the driver doesn't support flushes, return SUCCESS.
4173 //
4174
4175 if (Status == STATUS_INVALID_DEVICE_REQUEST) {
4176
4177 Status = STATUS_SUCCESS;
4178 }
4179
4180 Irp->IoStatus.Status = 0;
4181 Irp->IoStatus.Information = 0;
4182
4183 return Status;
4184 }
4185
4186