3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the low lever disk read/write support for Cdfs.
19 // The Bug check file id for this module
22 #define BugCheckFileId (CDFS_BUG_CHECK_DEVIOSUP)
25 // Local structure definitions
29 // An array of these structures is passed to CdMultipleAsync describing
30 // a set of runs to execute in parallel.
33 typedef struct _IO_RUN
{
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
45 // Current position in user buffer. This is the final destination for
46 // this portion of the Io transfer.
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.
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.
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.
67 // TransferBufferOffset - Offset in this buffer to begin the transfer
68 // to the user's buffer.
72 ULONG TransferByteCount
;
73 ULONG TransferBufferOffset
;
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.
85 PVOID TransferVirtualAddress
;
88 // Associated Irp used to perform the Io.
94 typedef IO_RUN
*PIO_RUN
;
96 #define MAX_PARALLEL_IOS 5
99 // Local support routines
102 _Requires_lock_held_(_Global_critical_region_
)
105 _In_ PIRP_CONTEXT IrpContext
,
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
117 _Requires_lock_held_(_Global_critical_region_
)
120 _In_ PIRP_CONTEXT IrpContext
,
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
134 _In_ PIRP_CONTEXT IrpContext
,
135 _Inout_ PIO_RUN IoRuns
,
137 _In_ BOOLEAN FinalCleanup
,
138 _In_ BOOLEAN SaveXABuffer
141 _Requires_lock_held_(_Global_critical_region_
)
144 _In_ PIRP_CONTEXT IrpContext
,
147 _Inout_ PIO_RUN IoRuns
152 _In_ PIRP_CONTEXT IrpContext
,
154 _Inout_ PIO_RUN IoRuns
,
155 _In_ PRAW_READ_INFO RawReads
,
156 _In_ TRACK_MODE_TYPE TrackMode
159 _Requires_lock_held_(_Global_critical_region_
)
162 _In_ PIRP_CONTEXT IrpContext
,
169 _In_ PIRP_CONTEXT IrpContext
172 // Tell prefast this is a completion routine.
173 IO_COMPLETION_ROUTINE CdMultiSyncCompletionRoutine
;
175 // Tell prefast this is a completion routine
176 IO_COMPLETION_ROUTINE CdMultiAsyncCompletionRoutine
;
178 // Tell prefast this is a completion routine
179 IO_COMPLETION_ROUTINE CdSingleSyncCompletionRoutine
;
181 // Tell prefast this is a completion routine
182 IO_COMPLETION_ROUTINE CdSingleAsyncCompletionRoutine
;
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
)))
187 CdReadAudioSystemFile (
188 _In_ PIRP_CONTEXT IrpContext
,
190 _In_ LONGLONG StartingOffset
,
191 _In_
_In_range_(>=, CdAudioDirentSize
) ULONG ByteCount
,
192 _Out_writes_bytes_(ByteCount
) PVOID SystemBuffer
195 _Requires_lock_held_(_Global_critical_region_
)
197 CdReadDirDataThroughCache (
198 _In_ PIRP_CONTEXT IrpContext
,
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)
228 _Out_writes_(3) PUCHAR Msf
235 Convert Lbn to MSF format.
239 Msf - on output, set to 0xMmSsFf representation of blocks.
246 Blocks
+= 150; // Lbn 0 == 00:02:00, 1sec == 75 frames.
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
266 This routine converts FCB XA file type flags to the track mode
267 used by the device drivers.
271 Fcb - Fcb representing the file to read.
275 TrackMode of the file represented by the Fcb.
279 NT_ASSERT( FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
|
280 FCB_STATE_MODE2_FILE
|
281 FCB_STATE_DA_FILE
));
283 if (FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
)) {
287 } else if (FlagOn( Fcb
->FcbState
, FCB_STATE_DA_FILE
)) {
294 // FCB_STATE_MODE2_FILE
301 _Requires_lock_held_(_Global_critical_region_
)
304 _In_ PIRP_CONTEXT IrpContext
,
306 _In_ LONGLONG StartingOffset
,
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.
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.
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.
328 Fcb - Fcb representing the file to read.
330 StartingOffset - Logical offset in the file to read from.
332 ByteCount - Number of bytes to read.
336 NTSTATUS - Status indicating the result of the operation.
341 NTSTATUS Status
= STATUS_SUCCESS
;
343 IO_RUN IoRuns
[MAX_PARALLEL_IOS
];
345 ULONG CleanupRunCount
= 0;
348 ULONG UserBufferOffset
= 0;
349 LONGLONG CurrentOffset
= StartingOffset
;
350 ULONG RemainingByteCount
= ByteCount
;
354 BOOLEAN FlushIoBuffers
= FALSE
;
355 BOOLEAN FirstPass
= TRUE
;
360 // We want to make sure the user's buffer is locked in all cases.
363 if (IrpContext
->Irp
->MdlAddress
== NULL
) {
365 CdCreateUserMdl( IrpContext
, ByteCount
, TRUE
, IoWriteAccess
);
368 CdMapUserBuffer( IrpContext
, &UserBuffer
);
371 // Special case the root directory and path table for a music volume.
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
))) {
378 CdReadAudioSystemFile( IrpContext
,
384 return STATUS_SUCCESS
;
388 // If we're going to use the sector cache for this request, then
389 // mark the request waitable.
392 if ((SafeNodeType( Fcb
) == CDFS_NTC_FCB_INDEX
) &&
393 (NULL
!= Fcb
->Vcb
->SectorCacheBuffer
) &&
394 (VcbMounted
== IrpContext
->Vcb
->VcbCondition
)) {
396 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
398 KeInitializeEvent( &IrpContext
->IoContext
->SyncEvent
,
402 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
407 // Use a try-finally to perform the final cleanup.
413 // Loop while there are more bytes to transfer.
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.
425 RtlZeroMemory( IoRuns
, sizeof( IoRuns
));
427 Unaligned
= CdPrepareBuffers( IrpContext
,
439 RunCount
= CleanupRunCount
;
442 // If this is an async request and there aren't enough entries
443 // in the Io array then post the request.
446 if ((ThisByteCount
< RemainingByteCount
) &&
447 !FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
449 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
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.
458 if ((RunCount
== 1) && !Unaligned
&& FirstPass
) {
460 CdSingleAsync( IrpContext
,&IoRuns
[0], Fcb
);
463 // No cleanup needed for the IoRuns array here.
469 // Wait if we are synchronous, otherwise return
472 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
474 CdWaitSync( IrpContext
);
476 Status
= IrpContext
->Irp
->IoStatus
.Status
;
479 // Our completion routine will free the Io context but
480 // we do want to return STATUS_PENDING.
485 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
486 Status
= STATUS_PENDING
;
489 try_return( NOTHING
);
493 // Otherwise we will perform multiple Io to read in the data.
496 CdMultipleAsync( IrpContext
, Fcb
, RunCount
, IoRuns
);
499 // If this is a synchronous request then perform any necessary
503 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
506 // Wait for the request to complete.
509 CdWaitSync( IrpContext
);
511 Status
= IrpContext
->Irp
->IoStatus
.Status
;
514 // Exit this loop if there is an error.
517 if (!NT_SUCCESS( Status
)) {
519 try_return( NOTHING
);
523 // Perform post read operations on the IoRuns if
528 CdFinishBuffers( IrpContext
, IoRuns
, RunCount
, FALSE
, FALSE
)) {
530 FlushIoBuffers
= TRUE
;
536 // Exit this loop if there are no more bytes to transfer
537 // or we have any error.
540 RemainingByteCount
-= ThisByteCount
;
541 CurrentOffset
+= ThisByteCount
;
542 UserBuffer
= Add2Ptr( UserBuffer
, ThisByteCount
, PVOID
);
543 UserBufferOffset
+= ThisByteCount
;
546 // Otherwise this is an asynchronous request. Always return
552 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
554 try_return( Status
= STATUS_PENDING
);
559 } while (RemainingByteCount
!= 0);
562 // Flush the hardware cache if we performed any copy operations.
565 if (FlushIoBuffers
) {
567 KeFlushIoBuffers( IrpContext
->Irp
->MdlAddress
, TRUE
, FALSE
);
574 // Perform final cleanup on the IoRuns if necessary.
577 if (CleanupRunCount
!= 0) {
579 CdFinishBuffers( IrpContext
, IoRuns
, CleanupRunCount
, TRUE
, FALSE
);
588 _Requires_lock_held_(_Global_critical_region_
)
591 _In_ PIRP_CONTEXT IrpContext
,
593 _In_ LONGLONG StartingOffset
,
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.
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.
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.
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.
618 Fcb - Fcb representing the file to read.
620 StartingOffset - Logical offset in the file to read from.
622 ByteCount - Number of bytes to read.
626 NTSTATUS - Status indicating the result of the operation.
631 NTSTATUS Status
= STATUS_SUCCESS
;
633 RIFF_HEADER LocalRiffHeader
;
634 PRIFF_HEADER RiffHeader
;
636 RAW_READ_INFO RawReads
[MAX_PARALLEL_IOS
];
637 IO_RUN IoRuns
[MAX_PARALLEL_IOS
];
639 ULONG CleanupRunCount
= 0;
642 ULONG UserBufferOffset
= 0;
643 LONGLONG CurrentOffset
= StartingOffset
;
644 ULONG RemainingByteCount
= ByteCount
;
645 ULONG ThisByteCount
= 0;
648 BOOLEAN TryingYellowbookMode2
= FALSE
;
650 TRACK_MODE_TYPE TrackMode
;
655 // We want to make sure the user's buffer is locked in all cases.
658 if (IrpContext
->Irp
->MdlAddress
== NULL
) {
660 CdCreateUserMdl( IrpContext
, ByteCount
, TRUE
, IoWriteAccess
);
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.
669 if (CurrentOffset
+ RemainingByteCount
> Fcb
->FileSize
.QuadPart
) {
671 RemainingByteCount
= (ULONG
) (Fcb
->FileSize
.QuadPart
- CurrentOffset
);
674 CdMapUserBuffer( IrpContext
, &UserBuffer
);
677 // Use a try-finally to perform the final cleanup.
683 // If the initial offset lies within the RIFF header then copy the
684 // necessary bytes to the user's buffer.
687 if (CurrentOffset
< sizeof( RIFF_HEADER
)) {
690 // Copy the appropriate RIFF header.
693 if (FlagOn( Fcb
->FcbState
, FCB_STATE_DA_FILE
)) {
696 // Create the pseudo entries for a music disk.
699 if (FlagOn( Fcb
->Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
701 PAUDIO_PLAY_HEADER AudioPlayHeader
;
702 PTRACK_DATA TrackData
;
704 AudioPlayHeader
= (PAUDIO_PLAY_HEADER
) &LocalRiffHeader
;
705 TrackData
= &Fcb
->Vcb
->CdromToc
->TrackData
[Fcb
->XAFileNumber
];
708 // Copy the data header into our local buffer.
711 RtlCopyMemory( AudioPlayHeader
,
713 sizeof( AUDIO_PLAY_HEADER
));
716 // Copy the serial number into the Id field. Also
717 // the track number in the TOC.
720 AudioPlayHeader
->DiskID
= Fcb
->Vcb
->Vpb
->SerialNumber
;
721 AudioPlayHeader
->TrackNumber
= TrackData
->TrackNumber
;
724 // One frame == One sector.
725 // One second == 75 frames (winds up being a 44.1khz sample)
727 // Note: LBN 0 == 0:2:0 (MSF)
731 // Fill in the address (both MSF and Lbn format) and length fields.
734 SwapCopyUchar4( &Address
, TrackData
->Address
);
735 CdLbnToMmSsFf( Address
, AudioPlayHeader
->TrackAddress
);
737 SwapCopyUchar4( &AudioPlayHeader
->StartingSector
, TrackData
->Address
);
740 // Go to the next track and find the starting point.
743 TrackData
= &Fcb
->Vcb
->CdromToc
->TrackData
[Fcb
->XAFileNumber
+ 1];
745 SwapCopyUchar4( &AudioPlayHeader
->SectorCount
, TrackData
->Address
);
748 // Now compute the difference. If there is an error then use
752 if (AudioPlayHeader
->SectorCount
< AudioPlayHeader
->StartingSector
) {
754 AudioPlayHeader
->SectorCount
= 0;
758 AudioPlayHeader
->SectorCount
-= AudioPlayHeader
->StartingSector
;
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;
766 Address
= AudioPlayHeader
->SectorCount
- 150;
767 CdLbnToMmSsFf( Address
, AudioPlayHeader
->TrackLength
);
769 ThisByteCount
= sizeof( RIFF_HEADER
) - (ULONG
) CurrentOffset
;
771 RtlCopyMemory( UserBuffer
,
772 Add2Ptr( AudioPlayHeader
,
773 sizeof( RIFF_HEADER
) - ThisByteCount
,
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.
788 RiffHeader
= &LocalRiffHeader
;
791 // Copy the data header into our local buffer and add the file size to it.
794 RtlCopyMemory( RiffHeader
,
795 CdXAAudioPhileHeader
,
796 sizeof( RIFF_HEADER
));
798 RiffHeader
->ChunkSize
+= Fcb
->FileSize
.LowPart
;
799 RiffHeader
->RawSectors
+= Fcb
->FileSize
.LowPart
;
801 ThisByteCount
= sizeof( RIFF_HEADER
) - (ULONG
) CurrentOffset
;
802 RtlCopyMemory( UserBuffer
,
804 sizeof( RIFF_HEADER
) - ThisByteCount
,
815 NT_ASSERT( FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2_FILE
| FCB_STATE_MODE2FORM2_FILE
));
817 RiffHeader
= &LocalRiffHeader
;
820 // Copy the data header into our local buffer and add the file size to it.
823 RtlCopyMemory( RiffHeader
,
825 sizeof( RIFF_HEADER
));
827 RiffHeader
->ChunkSize
+= Fcb
->FileSize
.LowPart
;
828 RiffHeader
->RawSectors
+= Fcb
->FileSize
.LowPart
;
830 RiffHeader
->Attributes
= (USHORT
) Fcb
->XAAttributes
;
831 RiffHeader
->FileNumber
= (UCHAR
) Fcb
->XAFileNumber
;
833 ThisByteCount
= sizeof( RIFF_HEADER
) - (ULONG
) CurrentOffset
;
834 RtlCopyMemory( UserBuffer
,
836 sizeof( RIFF_HEADER
) - ThisByteCount
,
842 // Adjust the starting offset and byte count to reflect that
843 // we copied over the RIFF bytes.
846 UserBuffer
= Add2Ptr( UserBuffer
, ThisByteCount
, PVOID
);
847 UserBufferOffset
+= ThisByteCount
;
848 CurrentOffset
+= ThisByteCount
;
849 RemainingByteCount
-= ThisByteCount
;
853 // Set up the appropriate trackmode
856 TrackMode
= CdFileTrackMode(Fcb
);
859 // Loop while there are more bytes to transfer.
862 while (RemainingByteCount
!= 0) {
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.
871 if (!TryingYellowbookMode2
) {
873 RtlZeroMemory( IoRuns
, sizeof( IoRuns
));
874 RtlZeroMemory( RawReads
, sizeof( RawReads
));
876 CdPrepareXABuffers( IrpContext
,
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.
894 if (CleanupRunCount
!= 0) {
896 RunCount
= CleanupRunCount
;
898 CdMultipleXAAsync( IrpContext
,
904 // Wait for the request to complete.
907 CdWaitSync( IrpContext
);
909 Status
= IrpContext
->Irp
->IoStatus
.Status
;
912 // Exit this loop if there is an error.
915 if (!NT_SUCCESS( Status
)) {
917 if (!TryingYellowbookMode2
&&
918 FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
)) {
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.
927 TryingYellowbookMode2
= TRUE
;
928 TrackMode
= YellowMode2
;
931 // Clear our 'cumulative' error status value
934 IrpContext
->IoContext
->Status
= STATUS_SUCCESS
;
939 try_return( NOTHING
);
944 if (TryingYellowbookMode2
) {
947 // We succesfully got data when we tried switching the trackmode,
948 // so change the state of the FCB to remember that.
951 SetFlag( Fcb
->FcbState
, FCB_STATE_MODE2_FILE
);
952 ClearFlag( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
);
954 TryingYellowbookMode2
= FALSE
;
958 // Perform post read operations on the IoRuns if
962 CdFinishBuffers( IrpContext
, IoRuns
, RunCount
, FALSE
, TRUE
);
966 // Adjust our loop variants.
969 RemainingByteCount
-= ThisByteCount
;
970 CurrentOffset
+= ThisByteCount
;
971 UserBuffer
= Add2Ptr( UserBuffer
, ThisByteCount
, PVOID
);
972 UserBufferOffset
+= ThisByteCount
;
976 // Always flush the hardware cache.
979 KeFlushIoBuffers( IrpContext
->Irp
->MdlAddress
, TRUE
, FALSE
);
985 // Perform final cleanup on the IoRuns if necessary.
988 if (CleanupRunCount
!= 0) {
990 CdFinishBuffers( IrpContext
, IoRuns
, CleanupRunCount
, TRUE
, FALSE
);
997 _Requires_lock_held_(_Global_critical_region_
)
1000 _In_ PIRP_CONTEXT IrpContext
,
1002 _In_ LONGLONG StartingOffset
,
1003 _In_ ULONG ByteCount
1008 Routine Description:
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.
1016 Fcb - Fcb representing the file to read.
1018 StartingOffset - Logical offset in the file to read from.
1020 ByteCount - Number of bytes to read.
1024 NTSTATUS - Status indicating the result of the operation.
1035 // We want to make sure the user's buffer is locked in all cases.
1038 CdLockUserBuffer( IrpContext
, ByteCount
, IoReadAccess
);
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.
1046 RtlZeroMemory( &IoRun
, sizeof( IoRun
) );
1048 IoRun
.DiskOffset
= StartingOffset
;
1049 IoRun
.DiskByteCount
= ByteCount
;
1051 CdSingleAsync( IrpContext
, &IoRun
, Fcb
);
1054 // Wait if we are synchronous, otherwise return
1057 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
1059 CdWaitSync( IrpContext
);
1061 Status
= IrpContext
->Irp
->IoStatus
.Status
;
1064 // Our completion routine will free the Io context but
1065 // we do want to return STATUS_PENDING.
1070 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
1071 Status
= STATUS_PENDING
;
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
1091 Routine Description:
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.
1096 This routine is synchronous, it will not return until the operation
1097 is complete or until the operation fails.
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.
1105 StartingOffset - Logical offset on the disk to start the read. This
1106 must be on a sector boundary, no check is made here.
1108 ByteCount - Number of bytes to read. This is an integral number of
1109 2K sectors, no check is made here to confirm this.
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.
1115 Buffer - Buffer to transfer the disk data into.
1117 TargetDeviceObject - The device object for the volume to be read.
1121 BOOLEAN - Depending on 'RaiseOnError' flag above. TRUE if operation
1122 succeeded, FALSE otherwise.
1134 // Initialize the event.
1137 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
1140 // Attempt to allocate the IRP. If unsuccessful, raise
1141 // STATUS_INSUFFICIENT_RESOURCES.
1144 Irp
= IoBuildSynchronousFsdRequest( IRP_MJ_READ
,
1148 (PLARGE_INTEGER
) &StartingOffset
,
1150 &IrpContext
->Irp
->IoStatus
);
1154 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1158 // Ignore the change line (verify) for mount and verify requests
1161 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1164 // Send the request down to the driver. If an error occurs return
1165 // it to the caller.
1168 Status
= IoCallDriver( TargetDeviceObject
, Irp
);
1171 // If the status was STATUS_PENDING then wait on the event.
1174 if (Status
== STATUS_PENDING
) {
1176 Status
= KeWaitForSingleObject( &Event
,
1183 // On a successful wait pull the status out of the IoStatus block.
1186 if (NT_SUCCESS( Status
)) {
1188 Status
= IrpContext
->Irp
->IoStatus
.Status
;
1193 // Check whether we should raise in the error case.
1196 if (!NT_SUCCESS( Status
)) {
1200 CdNormalizeAndRaiseStatus( IrpContext
, Status
);
1204 // We don't raise, but return FALSE to indicate an error.
1210 // The operation completed successfully.
1222 _In_ PIRP_CONTEXT IrpContext
,
1223 _In_ ULONG BufferLength
,
1224 _In_ BOOLEAN RaiseOnError
,
1225 _In_ LOCK_OPERATION Operation
1230 Routine Description:
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.
1237 This routine is only called if there is not already an Mdl.
1241 BufferLength - Length of user buffer.
1243 RaiseOnError - Indicates if our caller wants this routine to raise on
1246 Operation - IoWriteAccess or IoReadAccess
1250 NTSTATUS - Status from this routine. Error status only returned if
1251 RaiseOnError is FALSE.
1256 NTSTATUS Status
= STATUS_INSUFFICIENT_RESOURCES
;
1261 UNREFERENCED_PARAMETER( Operation
);
1262 UNREFERENCED_PARAMETER( IrpContext
);
1264 ASSERT_IRP_CONTEXT( IrpContext
);
1265 ASSERT_IRP( IrpContext
->Irp
);
1266 NT_ASSERT( IrpContext
->Irp
->MdlAddress
== NULL
);
1269 // Allocate the Mdl, and Raise if we fail.
1272 Mdl
= IoAllocateMdl( IrpContext
->Irp
->UserBuffer
,
1281 // Now probe the buffer described by the Irp. If we get an exception,
1282 // deallocate the Mdl and return the appropriate "expected" status.
1287 MmProbeAndLockPages( Mdl
, IrpContext
->Irp
->RequestorMode
, IoWriteAccess
);
1289 Status
= STATUS_SUCCESS
;
1292 #pragma warning(suppress: 6320)
1294 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1296 Status
= _SEH2_GetExceptionCode();
1299 IrpContext
->Irp
->MdlAddress
= NULL
;
1301 if (!FsRtlIsNtstatusExpected( Status
)) {
1303 Status
= STATUS_INVALID_USER_BUFFER
;
1309 // Check if we are to raise or return
1312 if (Status
!= STATUS_SUCCESS
) {
1316 CdRaiseStatus( IrpContext
, Status
);
1321 // Return the status code.
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
1344 Routine Description:
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
1352 IoControlCode - Code to send to driver.
1354 Device - This is the device to send the request to.
1356 OutPutBuffer - Pointer to output buffer.
1358 OutputBufferLength - Length of output buffer above.
1360 InternalDeviceIoControl - Indicates if this is an internal or external
1363 OverrideVerify - Indicates if we should tell the driver not to return
1364 STATUS_VERIFY_REQUIRED for mount and verify.
1366 Iosb - If specified, we return the results of the operation here.
1370 NTSTATUS - Status returned by next lower driver.
1378 IO_STATUS_BLOCK LocalIosb
;
1379 PIO_STATUS_BLOCK IosbToUse
= &LocalIosb
;
1383 UNREFERENCED_PARAMETER( IrpContext
);
1386 // Check if the user gave us an Iosb.
1389 if (ARGUMENT_PRESENT( Iosb
)) {
1394 IosbToUse
->Status
= 0;
1395 IosbToUse
->Information
= 0;
1397 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
1399 Irp
= IoBuildDeviceIoControlRequest( IoControlCode
,
1405 InternalDeviceIoControl
,
1411 return STATUS_INSUFFICIENT_RESOURCES
;
1414 if (OverrideVerify
) {
1416 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1419 Status
= IoCallDriver( Device
, Irp
);
1422 // We check for device not ready by first checking Status
1423 // and then if status pending was returned, the Iosb status
1427 if (Status
== STATUS_PENDING
) {
1429 (VOID
) KeWaitForSingleObject( &Event
,
1433 (PLARGE_INTEGER
)NULL
);
1435 Status
= IosbToUse
->Status
;
1438 NT_ASSERT( !(OverrideVerify
&& (STATUS_VERIFY_REQUIRED
== Status
)));
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
1459 return CdPerformDevIoCtrlEx( IrpContext
,
1466 InternalDeviceIoControl
,
1474 // Local support routine
1477 _Requires_lock_held_(_Global_critical_region_
)
1480 _In_ PIRP_CONTEXT IrpContext
,
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
1494 Routine Description:
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.
1501 This routine will raise CANT_WAIT if an unaligned transfer is encountered
1502 and this request can't wait.
1506 Irp - Originating Irp for this request.
1508 Fcb - This is the Fcb for this data stream. It may be a file, directory,
1509 path table or the volume file.
1511 UserBuffer - Current position in the user's buffer.
1513 UserBufferOffset - Offset from the start of the original user buffer.
1515 StartingOffset - Offset in the stream to begin the read.
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.
1521 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1522 this routine is called.
1524 RunCount - Number of entries in the IoRuns array filled here.
1526 ThisByteCount - Number of bytes described by the IoRun entries. Will
1527 not exceed the ByteCount passed in.
1531 BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
1532 this is synchronous). FALSE otherwise.
1537 BOOLEAN FoundUnaligned
= FALSE
;
1538 PIO_RUN ThisIoRun
= IoRuns
;
1541 // Following indicate where we are in the current transfer. Current
1542 // position in the file and number of bytes yet to transfer from
1546 ULONG RemainingByteCount
= ByteCount
;
1547 LONGLONG CurrentFileOffset
= StartingOffset
;
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
1557 PVOID CurrentUserBuffer
= UserBuffer
;
1558 ULONG CurrentUserBufferOffset
= UserBufferOffset
;
1561 // The following is the next contiguous bytes on the disk to
1562 // transfer. Read from the allocation package.
1565 LONGLONG DiskOffset
= 0;
1566 ULONG CurrentByteCount
= RemainingByteCount
;
1571 // Initialize the RunCount and ByteCount.
1578 // Loop while there are more bytes to process or there are
1579 // available entries in the IoRun array.
1587 // Initialize the current position in the IoRuns array.
1588 // Find the user's buffer for this portion of the transfer.
1591 ThisIoRun
->UserBuffer
= CurrentUserBuffer
;
1594 // Find the allocation information for the current offset in the
1598 CdLookupAllocation( IrpContext
,
1602 &CurrentByteCount
);
1605 // Limit ourselves to the data requested.
1608 if (CurrentByteCount
> RemainingByteCount
) {
1610 CurrentByteCount
= RemainingByteCount
;
1614 // Handle the case where this is an unaligned transfer. The
1615 // following must all be true for this to be an aligned transfer.
1617 // Disk offset on a 2048 byte boundary (Start of transfer)
1619 // Byte count is a multiple of 2048 (Length of transfer)
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.
1626 if (FlagOn( (ULONG
) DiskOffset
, SECTOR_MASK
) ||
1627 (FlagOn( (ULONG
) CurrentByteCount
, SECTOR_MASK
) &&
1628 (CurrentByteCount
< SECTOR_SIZE
))) {
1630 NT_ASSERT( SafeNodeType(Fcb
) != CDFS_NTC_FCB_INDEX
);
1633 // If we can't wait then raise.
1636 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
1638 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
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
1648 ThisIoRun
->TransferBufferOffset
= SectorOffset( DiskOffset
);
1651 // Make sure this transfer ends on a sector boundary.
1654 ThisIoRun
->DiskOffset
= LlSectorTruncate( DiskOffset
);
1657 // We need to allocate an auxilary buffer for the next sector.
1658 // Read up to a page containing the partial data.
1661 ThisIoRun
->DiskByteCount
= SectorAlign( ThisIoRun
->TransferBufferOffset
+ CurrentByteCount
);
1663 if (ThisIoRun
->DiskByteCount
> PAGE_SIZE
) {
1665 ThisIoRun
->DiskByteCount
= PAGE_SIZE
;
1668 if (ThisIoRun
->TransferBufferOffset
+ CurrentByteCount
> ThisIoRun
->DiskByteCount
) {
1670 CurrentByteCount
= ThisIoRun
->DiskByteCount
- ThisIoRun
->TransferBufferOffset
;
1673 ThisIoRun
->TransferByteCount
= CurrentByteCount
;
1676 // Allocate a buffer for the non-aligned transfer.
1679 ThisIoRun
->TransferBuffer
= FsRtlAllocatePoolWithTag( CdNonPagedPool
, PAGE_SIZE
, TAG_IO_BUFFER
);
1682 // Allocate and build the Mdl to describe this buffer.
1685 ThisIoRun
->TransferMdl
= IoAllocateMdl( ThisIoRun
->TransferBuffer
,
1691 ThisIoRun
->TransferVirtualAddress
= ThisIoRun
->TransferBuffer
;
1693 if (ThisIoRun
->TransferMdl
== NULL
) {
1695 IrpContext
->Irp
->IoStatus
.Information
= 0;
1696 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1699 MmBuildMdlForNonPagedPool( ThisIoRun
->TransferMdl
);
1702 // Remember we found an unaligned transfer.
1705 FoundUnaligned
= TRUE
;
1708 // Otherwise we use the buffer and Mdl from the original request.
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
1719 CurrentByteCount
= SectorTruncate( CurrentByteCount
);
1722 // Read these sectors from the disk.
1725 ThisIoRun
->DiskOffset
= DiskOffset
;
1726 ThisIoRun
->DiskByteCount
= CurrentByteCount
;
1729 // Use the user's buffer and Mdl as our transfer buffer
1733 ThisIoRun
->TransferBuffer
= CurrentUserBuffer
;
1734 ThisIoRun
->TransferMdl
= Irp
->MdlAddress
;
1735 ThisIoRun
->TransferVirtualAddress
= Add2Ptr( Irp
->UserBuffer
,
1736 CurrentUserBufferOffset
,
1741 // Update our position in the transfer and the RunCount and
1742 // ByteCount for the user.
1745 RemainingByteCount
-= CurrentByteCount
;
1748 // Break out if no more positions in the IoRuns array or
1749 // we have all of the bytes accounted for.
1752 *ThisByteCount
+= CurrentByteCount
;
1754 if ((RemainingByteCount
== 0) || (*RunCount
== MAX_PARALLEL_IOS
)) {
1760 // Update our pointers for the user's buffer.
1764 CurrentUserBuffer
= Add2Ptr( CurrentUserBuffer
, CurrentByteCount
, PVOID
);
1765 CurrentUserBufferOffset
+= CurrentByteCount
;
1766 CurrentFileOffset
+= CurrentByteCount
;
1769 return FoundUnaligned
;
1774 // Local support routine
1777 _Requires_lock_held_(_Global_critical_region_
)
1779 CdPrepareXABuffers (
1780 _In_ PIRP_CONTEXT IrpContext
,
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
1794 Routine Description:
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.
1805 Irp - Originating Irp for this request.
1807 Fcb - This is the Fcb for this data stream. It must be a data stream.
1809 UserBuffer - Current position in the user's buffer.
1811 UserBufferOffset - Offset of this buffer from the beginning of the user's
1812 buffer for the original request.
1814 StartingOffset - Offset in the stream to begin the read.
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.
1820 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1821 this routine is called.
1823 RunCount - Number of entries in the IoRuns array filled here.
1825 ThisByteCount - Number of bytes described by the IoRun entries. Will
1826 not exceed the ByteCount passed in.
1835 PIO_RUN ThisIoRun
= IoRuns
;
1836 BOOLEAN PerformedCopy
;
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.
1844 ULONG RawSectorOffset
;
1845 ULONG RemainingRawByteCount
= ByteCount
;
1846 LONGLONG CurrentRawOffset
= StartingOffset
- sizeof( RIFF_HEADER
);
1849 // The following is the offset into the cooked sectors for the file.
1852 LONGLONG CurrentCookedOffset
;
1853 ULONG RemainingCookedByteCount
;
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.
1862 PVOID CurrentUserBuffer
= UserBuffer
;
1863 ULONG CurrentUserBufferOffset
= UserBufferOffset
;
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.
1871 LONGLONG DiskOffset
= 0;
1872 ULONG CurrentCookedByteCount
= 0;
1873 ULONG CurrentRawByteCount
;
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.
1883 // Try to do 32-bit math.
1886 if (((PLARGE_INTEGER
) &CurrentRawOffset
)->HighPart
== 0) {
1889 // Prefix/fast: Note that the following are safe since we only
1890 // take this path for 32bit offsets.
1893 CurrentRawOffset
= (LONGLONG
) ((ULONG
) CurrentRawOffset
/ RAW_SECTOR_SIZE
);
1896 #pragma prefast( suppress: __WARNING_RESULTOFSHIFTCASTTOLARGERSIZE, "This is fine beacuse raw sector size > sector shift" )
1898 CurrentCookedOffset
= (LONGLONG
) ((ULONG
) CurrentRawOffset
<< SECTOR_SHIFT
);
1900 CurrentRawOffset
= (LONGLONG
) ((ULONG
) CurrentRawOffset
* RAW_SECTOR_SIZE
);
1903 // Otherwise we need to do 64-bit math (sigh).
1908 CurrentRawOffset
/= RAW_SECTOR_SIZE
;
1910 CurrentCookedOffset
= CurrentRawOffset
<< SECTOR_SHIFT
;
1912 CurrentRawOffset
*= RAW_SECTOR_SIZE
;
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.
1920 RawSectorOffset
= (ULONG
) ( StartingOffset
- CurrentRawOffset
) - sizeof( RIFF_HEADER
);
1921 CurrentRawByteCount
= (RawSectorOffset
+ RemainingRawByteCount
+ RAW_SECTOR_SIZE
- 1) / RAW_SECTOR_SIZE
;
1923 RemainingCookedByteCount
= CurrentRawByteCount
<< SECTOR_SHIFT
;
1926 // Initialize the RunCount and ByteCount.
1933 // Loop while there are more bytes to process or there are
1934 // available entries in the IoRun array.
1939 PerformedCopy
= FALSE
;
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.
1947 ThisIoRun
->UserBuffer
= CurrentUserBuffer
;
1950 // Find the allocation information for the current offset in the
1954 CdLookupAllocation( IrpContext
,
1956 CurrentCookedOffset
,
1958 &CurrentCookedByteCount
);
1960 // Maybe we got lucky and this is the same sector as in the
1964 if (DiskOffset
== Fcb
->Vcb
->XADiskOffset
) {
1967 // We will perform safe synchronization. Check again that
1968 // this is the correct sector.
1971 CdLockVcb( IrpContext
, Fcb
->Vcb
);
1973 if ((DiskOffset
== Fcb
->Vcb
->XADiskOffset
) &&
1974 (Fcb
->Vcb
->XASector
!= NULL
)) {
1977 // Copy any bytes we can from the current sector.
1980 CurrentRawByteCount
= RAW_SECTOR_SIZE
- RawSectorOffset
;
1983 // Check whether we don't go to the end of the sector.
1986 if (CurrentRawByteCount
> RemainingRawByteCount
) {
1988 CurrentRawByteCount
= RemainingRawByteCount
;
1991 RtlCopyMemory( CurrentUserBuffer
,
1992 Add2Ptr( Fcb
->Vcb
->XASector
, RawSectorOffset
, PCHAR
),
1993 CurrentRawByteCount
);
1995 CdUnlockVcb( IrpContext
, Fcb
->Vcb
);
1998 // Adjust the run count and pointer in the IoRuns array
1999 // to show that we didn't use a position.
2006 // Remember that we performed a copy operation.
2009 PerformedCopy
= TRUE
;
2011 CurrentCookedByteCount
= SECTOR_SIZE
;
2016 // The safe test showed no available buffer. Drop down to common code to
2020 CdUnlockVcb( IrpContext
, Fcb
->Vcb
);
2025 // No work in this pass if we did a copy operation.
2028 if (!PerformedCopy
) {
2031 // Limit ourselves by the number of remaining cooked bytes.
2034 if (CurrentCookedByteCount
> RemainingCookedByteCount
) {
2036 CurrentCookedByteCount
= RemainingCookedByteCount
;
2039 ThisIoRun
->DiskOffset
= DiskOffset
;
2040 ThisIoRun
->TransferBufferOffset
= RawSectorOffset
;
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.
2049 // We can use the user's buffer (at the current scratch buffer) if the
2050 // following are true:
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
2059 if ((RawSectorOffset
== 0) &&
2060 (RemainingRawByteCount
>= RAW_SECTOR_SIZE
)) {
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
2068 if (CurrentCookedByteCount
<= Fcb
->Vcb
->MaximumTransferRawSectors
* SECTOR_SIZE
) {
2070 CurrentRawByteCount
= (SectorAlign( CurrentCookedByteCount
) >> SECTOR_SHIFT
) * RAW_SECTOR_SIZE
;
2074 CurrentCookedByteCount
= Fcb
->Vcb
->MaximumTransferRawSectors
* SECTOR_SIZE
;
2075 CurrentRawByteCount
= Fcb
->Vcb
->MaximumTransferRawSectors
* RAW_SECTOR_SIZE
;
2079 // Now make sure we are within the page transfer limit.
2082 while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentUserBuffer
, RawSectorAlign( CurrentRawByteCount
)) >
2083 Fcb
->Vcb
->MaximumPhysicalPages
) {
2085 CurrentRawByteCount
-= RAW_SECTOR_SIZE
;
2086 CurrentCookedByteCount
-= SECTOR_SIZE
;
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.
2094 while (RawSectorAlign( CurrentRawByteCount
) > RemainingRawByteCount
) {
2096 CurrentRawByteCount
-= RAW_SECTOR_SIZE
;
2097 CurrentCookedByteCount
-= SECTOR_SIZE
;
2101 // Now trim the maximum number of raw bytes to the remaining bytes.
2104 if (CurrentRawByteCount
> RemainingRawByteCount
) {
2106 CurrentRawByteCount
= RemainingRawByteCount
;
2110 // Update the IO run array. We point to the scratch buffer as
2111 // well as the buffer and Mdl in the original Irp.
2114 ThisIoRun
->DiskByteCount
= SectorAlign( CurrentCookedByteCount
);
2117 // Point to the user's buffer and Mdl for this transfer.
2120 ThisIoRun
->TransferBuffer
= CurrentUserBuffer
;
2121 ThisIoRun
->TransferMdl
= Irp
->MdlAddress
;
2122 ThisIoRun
->TransferVirtualAddress
= Add2Ptr( Irp
->UserBuffer
,
2123 CurrentUserBufferOffset
,
2129 // We need to determine the number of bytes to transfer and the
2130 // offset into this page to begin the transfer.
2132 // We will transfer only one raw sector.
2135 ThisIoRun
->DiskByteCount
= SECTOR_SIZE
;
2137 CurrentCookedByteCount
= SECTOR_SIZE
;
2139 ThisIoRun
->TransferByteCount
= RAW_SECTOR_SIZE
- RawSectorOffset
;
2140 ThisIoRun
->TransferBufferOffset
= RawSectorOffset
;
2142 if (ThisIoRun
->TransferByteCount
> RemainingRawByteCount
) {
2144 ThisIoRun
->TransferByteCount
= RemainingRawByteCount
;
2147 CurrentRawByteCount
= ThisIoRun
->TransferByteCount
;
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.
2154 ThisIoRun
->TransferBuffer
= FsRtlAllocatePoolWithTag( CdNonPagedPool
, PAGE_SIZE
, TAG_IO_BUFFER
);
2157 // Allocate and build the Mdl to describe this buffer.
2160 ThisIoRun
->TransferMdl
= IoAllocateMdl( ThisIoRun
->TransferBuffer
,
2166 ThisIoRun
->TransferVirtualAddress
= ThisIoRun
->TransferBuffer
;
2168 if (ThisIoRun
->TransferMdl
== NULL
) {
2170 IrpContext
->Irp
->IoStatus
.Information
= 0;
2171 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2174 MmBuildMdlForNonPagedPool( ThisIoRun
->TransferMdl
);
2179 // Update the byte count for our caller.
2182 RemainingRawByteCount
-= CurrentRawByteCount
;
2183 *ThisByteCount
+= CurrentRawByteCount
;
2186 // Break out if no more positions in the IoRuns array or
2187 // we have all of the bytes accounted for.
2190 if ((RemainingRawByteCount
== 0) || (*RunCount
== MAX_PARALLEL_IOS
)) {
2196 // Update our local pointers to allow for the current range of bytes.
2201 CurrentUserBuffer
= Add2Ptr( CurrentUserBuffer
, CurrentRawByteCount
, PVOID
);
2202 CurrentUserBufferOffset
+= CurrentRawByteCount
;
2204 RawSectorOffset
= 0;
2206 CurrentCookedOffset
+= CurrentCookedByteCount
;
2207 RemainingCookedByteCount
-= CurrentCookedByteCount
;
2215 // Local support routine
2220 _In_ PIRP_CONTEXT IrpContext
,
2221 _Inout_ PIO_RUN IoRuns
,
2222 _In_ ULONG RunCount
,
2223 _In_ BOOLEAN FinalCleanup
,
2224 _In_ BOOLEAN SaveXABuffer
2229 Routine Description:
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.
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.
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.
2246 IoRuns - Pointer to the IoRuns array.
2248 RunCount - Number of entries in the IoRuns array filled here.
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
2255 SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
2259 BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
2264 BOOLEAN FlushIoBuffers
= FALSE
;
2266 ULONG RemainingEntries
= RunCount
;
2267 PIO_RUN ThisIoRun
= &IoRuns
[RunCount
- 1];
2273 // Walk through each entry in the IoRun array.
2276 while (RemainingEntries
!= 0) {
2279 // We only need to deal with the case of an unaligned transfer.
2282 if (ThisIoRun
->TransferByteCount
!= 0) {
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.
2290 if (!FinalCleanup
) {
2292 RtlCopyMemory( ThisIoRun
->UserBuffer
,
2293 Add2Ptr( ThisIoRun
->TransferBuffer
,
2294 ThisIoRun
->TransferBufferOffset
,
2296 ThisIoRun
->TransferByteCount
);
2298 FlushIoBuffers
= TRUE
;
2302 // Free any Mdl we may have allocated. If the Mdl isn't
2303 // present then we must have failed during the allocation
2307 if (ThisIoRun
->TransferMdl
!= IrpContext
->Irp
->MdlAddress
) {
2309 if (ThisIoRun
->TransferMdl
!= NULL
) {
2311 IoFreeMdl( ThisIoRun
->TransferMdl
);
2315 // Now free any buffer we may have allocated. If the Mdl
2316 // doesn't match the original Mdl then free the buffer.
2319 if (ThisIoRun
->TransferBuffer
!= NULL
) {
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.
2329 Vcb
= IrpContext
->Vcb
;
2331 CdLockVcb( IrpContext
, Vcb
);
2333 if (Vcb
->XASector
!= NULL
) {
2335 CdFreePool( &Vcb
->XASector
);
2338 Vcb
->XASector
= ThisIoRun
->TransferBuffer
;
2339 Vcb
->XADiskOffset
= ThisIoRun
->DiskOffset
;
2341 SaveXABuffer
= FALSE
;
2343 CdUnlockVcb( IrpContext
, Vcb
);
2346 // Otherwise just free the buffer.
2351 CdFreePool( &ThisIoRun
->TransferBuffer
);
2358 // Now handle the case where we failed in the process
2359 // of allocating associated Irps and Mdls.
2362 if (ThisIoRun
->SavedIrp
!= NULL
) {
2364 if (ThisIoRun
->SavedIrp
->MdlAddress
!= NULL
) {
2366 IoFreeMdl( ThisIoRun
->SavedIrp
->MdlAddress
);
2369 IoFreeIrp( ThisIoRun
->SavedIrp
);
2373 // Move to the previous IoRun entry.
2377 RemainingEntries
-= 1;
2381 // If we copied any data then flush the Io buffers.
2384 return FlushIoBuffers
;
2387 // Tell prefast this is a completion routine.
2388 IO_COMPLETION_ROUTINE CdSyncCompletionRoutine
;
2391 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
2392 CdSyncCompletionRoutine (
2393 PDEVICE_OBJECT DeviceObject
,
2400 Routine Description:
2402 Completion routine for synchronizing back to dispatch.
2406 Contxt - pointer to KEVENT.
2410 STATUS_MORE_PROCESSING_REQUIRED
2415 PKEVENT Event
= (PKEVENT
)Contxt
;
2416 _Analysis_assume_(Contxt
!= NULL
);
2418 UNREFERENCED_PARAMETER( Irp
);
2419 UNREFERENCED_PARAMETER( DeviceObject
);
2421 KeSetEvent( Event
, 0, FALSE
);
2424 // We don't want IO to get our IRP and free it.
2427 return STATUS_MORE_PROCESSING_REQUIRED
;
2431 _Requires_lock_held_(_Global_critical_region_
)
2434 _In_ PIRP_CONTEXT IrpContext
2439 Routine Description:
2441 Safely frees the sector cache buffer.
2454 if (NULL
!= IrpContext
->Vcb
->SectorCacheBuffer
) {
2456 CdAcquireCacheForUpdate( IrpContext
);
2457 CdFreePool( &IrpContext
->Vcb
->SectorCacheBuffer
);
2458 CdReleaseCache( IrpContext
);
2462 _Requires_lock_held_(_Global_critical_region_
)
2464 CdReadDirDataThroughCache (
2465 _In_ PIRP_CONTEXT IrpContext
,
2471 Routine Description:
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
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.
2484 Run - description of extent required, and buffer to read into.
2488 None. Raises on error.
2493 PVCB Vcb
= IrpContext
->Vcb
;
2494 ULONG Lbn
= SectorsFromLlBytes( Run
->DiskOffset
);
2495 ULONG Remaining
= SectorsFromBytes( Run
->DiskByteCount
);
2496 PUCHAR UserBuffer
= Run
->TransferBuffer
;
2500 ULONG BufferSectorOffset
;
2505 PIO_STACK_LOCATION IrpSp
;
2506 IO_STATUS_BLOCK Iosb
;
2508 PTRACK_DATA TrackData
;
2511 BOOLEAN JustRead
= FALSE
;
2515 PCD_SECTOR_CACHE_CHUNK Buffer
;
2516 BOOLEAN Result
= FALSE
;
2520 CdAcquireCacheForRead( IrpContext
);
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.
2530 if (NULL
== Vcb
->SectorCacheBuffer
) {
2532 CdRaiseStatus( IrpContext
, STATUS_VERIFY_REQUIRED
);
2540 // Look to see if any portion is currently cached.
2543 for (Index
= 0; Index
< CD_SEC_CACHE_CHUNKS
; Index
++) {
2545 if ((Vcb
->SecCacheChunks
[ Index
].BaseLbn
!= -1) &&
2546 (Vcb
->SecCacheChunks
[ Index
].BaseLbn
<= Lbn
) &&
2547 ((Vcb
->SecCacheChunks
[ Index
].BaseLbn
+ CD_SEC_CHUNK_BLOCKS
) > Lbn
)) {
2549 Buffer
= &Vcb
->SecCacheChunks
[ Index
];
2555 // If we found any, copy it out and continue.
2558 if (NULL
!= Buffer
) {
2560 BufferSectorOffset
= Lbn
- Buffer
->BaseLbn
;
2561 Found
= Min( CD_SEC_CHUNK_BLOCKS
- BufferSectorOffset
, Remaining
);
2563 RtlCopyMemory( UserBuffer
,
2564 Buffer
->Buffer
+ BytesFromSectors( BufferSectorOffset
),
2565 BytesFromSectors( Found
));
2568 UserBuffer
+= BytesFromSectors( Found
);
2572 // Update stats. Don't count a hit if we've just read the data in.
2577 InterlockedIncrement( (LONG
*)&Vcb
->SecCacheHits
);
2586 // Missed the cache, so we need to read a new chunk. Take the cache
2587 // resource exclusive while we do so.
2590 CdReleaseCache( IrpContext
);
2591 CdAcquireCacheForUpdate( IrpContext
);
2593 Vcb
->SecCacheMisses
+= 1;
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
2602 Buffer
= &Vcb
->SecCacheChunks
[ Vcb
->SecCacheLRUChunkIndex
];
2604 StartBlock
= Lbn
- ((Lbn
- 16) % CD_SEC_CHUNK_BLOCKS
);
2607 // Make sure we don't try and read past end of the last track.
2611 if (Vcb
->CdromToc
) {
2613 TrackData
= &Vcb
->CdromToc
->TrackData
[(Vcb
->CdromToc
->LastTrack
- Vcb
->CdromToc
->FirstTrack
+ 1)];
2615 SwapCopyUchar4( &EndBlock
, &TrackData
->Address
);
2617 Blocks
= EndBlock
- StartBlock
;
2619 if (Blocks
> CD_SEC_CHUNK_BLOCKS
) {
2621 Blocks
= CD_SEC_CHUNK_BLOCKS
;
2625 // HACK!!!!!!!! Might cause reads to overrun the end of the partition, no idea what consequences that can have.
2626 Blocks
= CD_SEC_CHUNK_BLOCKS
;
2630 if ((0 == Blocks
) || (Lbn
< 16)) {
2632 CdRaiseStatus( IrpContext
, STATUS_INVALID_PARAMETER
);
2636 // Now build / send the read request.
2639 IoReuseIrp( Vcb
->SectorCacheIrp
, STATUS_SUCCESS
);
2641 KeClearEvent( &Vcb
->SectorCacheEvent
);
2642 Vcb
->SectorCacheIrp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
2645 // Get a pointer to the stack location of the first driver which will be
2646 // invoked. This is where the function codes and the parameters are set.
2649 IrpSp
= IoGetNextIrpStackLocation( Vcb
->SectorCacheIrp
);
2650 IrpSp
->MajorFunction
= (UCHAR
) IRP_MJ_READ
;
2653 // Build an MDL to describe the buffer.
2656 IoAllocateMdl( Buffer
->Buffer
,
2657 BytesFromSectors( Blocks
),
2660 Vcb
->SectorCacheIrp
);
2662 if (NULL
== Vcb
->SectorCacheIrp
->MdlAddress
) {
2664 IrpContext
->Irp
->IoStatus
.Information
= 0;
2665 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2669 // We're reading/writing into the block cache (paged pool). Lock the
2670 // pages and update the MDL with physical page information.
2675 MmProbeAndLockPages( Vcb
->SectorCacheIrp
->MdlAddress
,
2677 (LOCK_OPERATION
) IoWriteAccess
);
2680 #pragma warning(suppress: 6320)
2682 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2684 IoFreeMdl( Vcb
->SectorCacheIrp
->MdlAddress
);
2685 Vcb
->SectorCacheIrp
->MdlAddress
= NULL
;
2688 if (NULL
== Vcb
->SectorCacheIrp
->MdlAddress
) {
2690 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2694 // Reset the BaseLbn as we can't trust this Buffer's data until the request
2695 // is successfully completed.
2698 Buffer
->BaseLbn
= (ULONG
)-1;
2700 IrpSp
->Parameters
.Read
.Length
= BytesFromSectors( Blocks
);
2701 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= LlBytesFromSectors( StartBlock
);
2703 IoSetCompletionRoutine( Vcb
->SectorCacheIrp
,
2704 CdSyncCompletionRoutine
,
2705 &Vcb
->SectorCacheEvent
,
2710 Vcb
->SectorCacheIrp
->UserIosb
= &Iosb
;
2712 Status
= IoCallDriver( Vcb
->TargetDeviceObject
, Vcb
->SectorCacheIrp
);
2714 if (STATUS_PENDING
== Status
) {
2717 (VOID
)KeWaitForSingleObject( &Vcb
->SectorCacheEvent
,
2723 Status
= Vcb
->SectorCacheIrp
->IoStatus
.Status
;
2726 Vcb
->SectorCacheIrp
->UserIosb
= NULL
;
2729 // Unlock the pages and free the MDL.
2732 MmUnlockPages( Vcb
->SectorCacheIrp
->MdlAddress
);
2733 IoFreeMdl( Vcb
->SectorCacheIrp
->MdlAddress
);
2734 Vcb
->SectorCacheIrp
->MdlAddress
= NULL
;
2736 if (!NT_SUCCESS( Status
)) {
2738 try_leave( Status
);
2742 // Update the buffer information, and drop the cache resource to shared
2743 // to allow in reads.
2746 Buffer
->BaseLbn
= StartBlock
;
2747 Vcb
->SecCacheLRUChunkIndex
= (Vcb
->SecCacheLRUChunkIndex
+ 1) % CD_SEC_CACHE_CHUNKS
;
2749 CdConvertCacheToShared( IrpContext
);
2759 CdReleaseCache( IrpContext
);
2767 // Local support routine
2770 _Requires_lock_held_(_Global_critical_region_
)
2773 _In_ PIRP_CONTEXT IrpContext
,
2775 _In_ ULONG RunCount
,
2776 _Inout_ PIO_RUN IoRuns
2781 Routine Description:
2783 This routine first does the initial setup required of a Master IRP that is
2784 going to be completed using associated IRPs. This routine should not
2785 be used if only one async request is needed, instead the single read
2786 async routines should be called.
2788 A context parameter is initialized, to serve as a communications area
2789 between here and the common completion routine.
2791 Next this routine reads or writes one or more contiguous sectors from
2792 a device asynchronously, and is used if there are multiple reads for a
2793 master IRP. A completion routine is used to synchronize with the
2794 completion of all of the I/O requests started by calls to this routine.
2796 Also, prior to calling this routine the caller must initialize the
2797 IoStatus field in the Context, with the correct success status and byte
2798 count which are expected if all of the parallel transfers complete
2799 successfully. After return this status will be unchanged if all requests
2800 were, in fact, successful. However, if one or more errors occur, the
2801 IoStatus will be modified to reflect the error status and byte count
2802 from the first run (by Vbo) which encountered an error. I/O status
2803 from all subsequent runs will not be indicated.
2807 RunCount - Supplies the number of multiple async requests
2808 that will be issued against the master irp.
2810 IoRuns - Supplies an array containing the Offset and ByteCount for the
2820 PIO_COMPLETION_ROUTINE CompletionRoutine
;
2821 PIO_STACK_LOCATION IrpSp
;
2825 ULONG UnwindRunCount
;
2826 BOOLEAN UseSectorCache
;
2831 // Set up things according to whether this is truely async.
2834 CompletionRoutine
= CdMultiSyncCompletionRoutine
;
2836 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
2838 CompletionRoutine
= CdMultiAsyncCompletionRoutine
;
2842 // For directories, use the sector cache.
2845 if ((SafeNodeType( Fcb
) == CDFS_NTC_FCB_INDEX
) &&
2846 (NULL
!= Fcb
->Vcb
->SectorCacheBuffer
) &&
2847 (VcbMounted
== IrpContext
->Vcb
->VcbCondition
)) {
2849 UseSectorCache
= TRUE
;
2853 UseSectorCache
= FALSE
;
2857 // Initialize some local variables.
2860 MasterIrp
= IrpContext
->Irp
;
2863 // Itterate through the runs, doing everything that can fail.
2864 // We let the cleanup in CdFinishBuffers clean up on error.
2867 for (UnwindRunCount
= 0;
2868 UnwindRunCount
< RunCount
;
2869 UnwindRunCount
+= 1) {
2871 if (UseSectorCache
) {
2873 if (!CdReadDirDataThroughCache( IrpContext
, &IoRuns
[ UnwindRunCount
])) {
2876 // Turn off using directory cache and restart all over again.
2879 UseSectorCache
= FALSE
;
2887 // Create an associated IRP, making sure there is one stack entry for
2891 IoRuns
[UnwindRunCount
].SavedIrp
=
2892 Irp
= IoMakeAssociatedIrp( MasterIrp
, (CCHAR
)(IrpContext
->Vcb
->TargetDeviceObject
->StackSize
+ 1) );
2896 IrpContext
->Irp
->IoStatus
.Information
= 0;
2897 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2901 // Allocate and build a partial Mdl for the request.
2904 Mdl
= IoAllocateMdl( IoRuns
[UnwindRunCount
].TransferVirtualAddress
,
2905 IoRuns
[UnwindRunCount
].DiskByteCount
,
2912 IrpContext
->Irp
->IoStatus
.Information
= 0;
2913 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2916 IoBuildPartialMdl( IoRuns
[UnwindRunCount
].TransferMdl
,
2918 IoRuns
[UnwindRunCount
].TransferVirtualAddress
,
2919 IoRuns
[UnwindRunCount
].DiskByteCount
);
2922 // Get the first IRP stack location in the associated Irp
2925 IoSetNextIrpStackLocation( Irp
);
2926 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2929 // Setup the Stack location to describe our read.
2932 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2933 IrpSp
->Parameters
.Read
.Length
= IoRuns
[UnwindRunCount
].DiskByteCount
;
2934 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= IoRuns
[UnwindRunCount
].DiskOffset
;
2937 // Set up the completion routine address in our stack frame.
2940 IoSetCompletionRoutine( Irp
,
2942 IrpContext
->IoContext
,
2948 // Setup the next IRP stack location in the associated Irp for the disk
2949 // driver beneath us.
2952 IrpSp
= IoGetNextIrpStackLocation( Irp
);
2955 // Setup the Stack location to do a read from the disk driver.
2958 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2959 IrpSp
->Parameters
.Read
.Length
= IoRuns
[UnwindRunCount
].DiskByteCount
;
2960 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= IoRuns
[UnwindRunCount
].DiskOffset
;
2964 // If we used the cache, we're done.
2967 if (UseSectorCache
) {
2969 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
2971 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2972 KeSetEvent( &IrpContext
->IoContext
->SyncEvent
, 0, FALSE
);
2979 // We only need to set the associated IRP count in the master irp to
2980 // make it a master IRP. But we set the count to one more than our
2981 // caller requested, because we do not want the I/O system to complete
2982 // the I/O. We also set our own count.
2985 IrpContext
->IoContext
->IrpCount
= RunCount
;
2986 IrpContext
->IoContext
->MasterIrp
= MasterIrp
;
2989 // We set the count in the master Irp to 1 since typically we
2990 // will clean up the associated irps ourselves. Setting this to one
2991 // means completing the last associated Irp with SUCCESS (in the async
2992 // case) will complete the master irp.
2995 MasterIrp
->AssociatedIrp
.IrpCount
= 1;
2998 // If we (FS) acquired locks, transition the lock owners to an object, since
2999 // when we return this thread could go away before request completion, and
3000 // the resource package may otherwise try to boost priority, etc.
3003 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) &&
3004 FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL
)) {
3006 NT_ASSERT( IrpContext
->IoContext
->ResourceThreadId
== (ERESOURCE_THREAD
)PsGetCurrentThread() );
3008 IrpContext
->IoContext
->ResourceThreadId
= ((ULONG_PTR
)IrpContext
->IoContext
) | 3;
3010 ExSetResourceOwnerPointer( IrpContext
->IoContext
->Resource
,
3011 (PVOID
)IrpContext
->IoContext
->ResourceThreadId
);
3015 // Now that all the dangerous work is done, issue the Io requests
3018 for (UnwindRunCount
= 0;
3019 UnwindRunCount
< RunCount
;
3022 Irp
= IoRuns
[UnwindRunCount
].SavedIrp
;
3023 IoRuns
[UnwindRunCount
].SavedIrp
= NULL
;
3028 // If IoCallDriver returns an error, it has completed the Irp
3029 // and the error will be caught by our completion routines
3030 // and dealt with as a normal IO error.
3033 (VOID
) IoCallDriver( IrpContext
->Vcb
->TargetDeviceObject
, Irp
);
3040 // Local support routine
3045 _In_ PIRP_CONTEXT IrpContext
,
3046 _In_ ULONG RunCount
,
3047 _Inout_ PIO_RUN IoRuns
,
3048 _In_ PRAW_READ_INFO RawReads
,
3049 _In_ TRACK_MODE_TYPE TrackMode
3054 Routine Description:
3056 This routine first does the initial setup required of a Master IRP that is
3057 going to be completed using associated IRPs. This routine is used to generate
3058 the associated Irps used to read raw sectors from the disk.
3060 A context parameter is initialized, to serve as a communications area
3061 between here and the common completion routine.
3063 Next this routine reads or writes one or more contiguous sectors from
3064 a device asynchronously, and is used if there are multiple reads for a
3065 master IRP. A completion routine is used to synchronize with the
3066 completion of all of the I/O requests started by calls to this routine.
3068 Also, prior to calling this routine the caller must initialize the
3069 IoStatus field in the Context, with the correct success status and byte
3070 count which are expected if all of the parallel transfers complete
3071 successfully. After return this status will be unchanged if all requests
3072 were, in fact, successful. However, if one or more errors occur, the
3073 IoStatus will be modified to reflect the error status and byte count
3074 from the first run (by Vbo) which encountered an error. I/O status
3075 from all subsequent runs will not be indicated.
3079 RunCount - Supplies the number of multiple async requests
3080 that will be issued against the master irp.
3082 IoRuns - Supplies an array containing the Offset and ByteCount for the
3085 RawReads - Supplies an array of structures to store in the Irps passed to the
3086 device driver to perform the low-level Io.
3088 TrackMode - Supplies the recording mode of sectors in these IoRuns
3097 PIO_STACK_LOCATION IrpSp
;
3101 ULONG UnwindRunCount
;
3104 PIO_RUN ThisIoRun
= IoRuns
;
3105 PRAW_READ_INFO ThisRawRead
= RawReads
;
3110 // Initialize some local variables.
3113 MasterIrp
= IrpContext
->Irp
;
3116 // Itterate through the runs, doing everything that can fail.
3117 // We let the cleanup in CdFinishBuffers clean up on error.
3120 for (UnwindRunCount
= 0;
3121 UnwindRunCount
< RunCount
;
3122 UnwindRunCount
+= 1, ThisIoRun
+= 1, ThisRawRead
+= 1) {
3125 // Create an associated IRP, making sure there is one stack entry for
3129 ThisIoRun
->SavedIrp
=
3130 Irp
= IoMakeAssociatedIrp( MasterIrp
, (CCHAR
)(IrpContext
->Vcb
->TargetDeviceObject
->StackSize
+ 1) );
3134 IrpContext
->Irp
->IoStatus
.Information
= 0;
3135 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
3139 // Should have been passed a byte count of at least one sector, and
3140 // must be a multiple of sector size
3143 NT_ASSERT( ThisIoRun
->DiskByteCount
&& !SectorOffset(ThisIoRun
->DiskByteCount
));
3145 RawByteCount
= SectorsFromBytes( ThisIoRun
->DiskByteCount
) * RAW_SECTOR_SIZE
;
3148 // Allocate and build a partial Mdl for the request.
3151 Mdl
= IoAllocateMdl( ThisIoRun
->TransferVirtualAddress
,
3159 IrpContext
->Irp
->IoStatus
.Information
= 0;
3160 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
3163 IoBuildPartialMdl( ThisIoRun
->TransferMdl
,
3165 ThisIoRun
->TransferVirtualAddress
,
3168 // Get the first IRP stack location in the associated Irp
3171 IoSetNextIrpStackLocation( Irp
);
3172 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3175 // Setup the Stack location to describe our read (using cooked values)
3176 // These values won't be used for the raw read in any case.
3179 IrpSp
->MajorFunction
= IRP_MJ_READ
;
3180 IrpSp
->Parameters
.Read
.Length
= ThisIoRun
->DiskByteCount
;
3181 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= ThisIoRun
->DiskOffset
;
3184 // Set up the completion routine address in our stack frame.
3187 IoSetCompletionRoutine( Irp
,
3188 CdMultiSyncCompletionRoutine
,
3189 IrpContext
->IoContext
,
3195 // Setup the next IRP stack location in the associated Irp for the disk
3196 // driver beneath us.
3199 IrpSp
= IoGetNextIrpStackLocation( Irp
);
3202 // Setup the stack location to do a read of raw sectors at this location.
3203 // Note that the storage stack always reads multiples of whole XA sectors.
3206 ThisRawRead
->DiskOffset
.QuadPart
= ThisIoRun
->DiskOffset
;
3207 ThisRawRead
->SectorCount
= ThisIoRun
->DiskByteCount
>> SECTOR_SHIFT
;
3208 ThisRawRead
->TrackMode
= TrackMode
;
3210 IrpSp
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
3212 IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
= ThisRawRead
->SectorCount
* RAW_SECTOR_SIZE
;
3213 Irp
->UserBuffer
= ThisIoRun
->TransferVirtualAddress
;
3215 IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
= sizeof( RAW_READ_INFO
);
3216 IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
= ThisRawRead
;
3218 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_CDROM_RAW_READ
;
3222 // We only need to set the associated IRP count in the master irp to
3223 // make it a master IRP. But we set the count to one more than our
3224 // caller requested, because we do not want the I/O system to complete
3225 // the I/O. We also set our own count.
3228 IrpContext
->IoContext
->IrpCount
= RunCount
;
3229 IrpContext
->IoContext
->MasterIrp
= MasterIrp
;
3232 // We set the count in the master Irp to 1 since typically we
3233 // will clean up the associated irps ourselves. Setting this to one
3234 // means completing the last associated Irp with SUCCESS (in the async
3235 // case) will complete the master irp.
3238 MasterIrp
->AssociatedIrp
.IrpCount
= 1;
3241 // Now that all the dangerous work is done, issue the Io requests
3244 for (UnwindRunCount
= 0;
3245 UnwindRunCount
< RunCount
;
3248 Irp
= IoRuns
[UnwindRunCount
].SavedIrp
;
3249 IoRuns
[UnwindRunCount
].SavedIrp
= NULL
;
3253 // If IoCallDriver returns an error, it has completed the Irp
3254 // and the error will be caught by our completion routines
3255 // and dealt with as a normal IO error.
3258 (VOID
) IoCallDriver( IrpContext
->Vcb
->TargetDeviceObject
, Irp
);
3266 // Local support routine
3269 _Requires_lock_held_(_Global_critical_region_
)
3272 _In_ PIRP_CONTEXT IrpContext
,
3279 Routine Description:
3281 This routine reads one or more contiguous sectors from a device
3282 asynchronously, and is used if there is only one read necessary to
3283 complete the IRP. It implements the read by simply filling
3284 in the next stack frame in the Irp, and passing it on. The transfer
3285 occurs to the single buffer originally specified in the user request.
3289 ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
3291 ByteCount - Supplies the number of bytes to read from the device
3300 PIO_STACK_LOCATION IrpSp
;
3301 PIO_COMPLETION_ROUTINE CompletionRoutine
;
3306 // For directories, look in the sector cache,
3309 if ((SafeNodeType( Fcb
) == CDFS_NTC_FCB_INDEX
) &&
3310 (NULL
!= Fcb
->Vcb
->SectorCacheBuffer
) &&
3311 (VcbMounted
== IrpContext
->Vcb
->VcbCondition
)) {
3313 if (CdReadDirDataThroughCache( IrpContext
, Run
)) {
3315 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
3317 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3318 KeSetEvent( &IrpContext
->IoContext
->SyncEvent
, 0, FALSE
);
3326 // Set up things according to whether this is truely async.
3329 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
3331 CompletionRoutine
= CdSingleSyncCompletionRoutine
;
3335 CompletionRoutine
= CdSingleAsyncCompletionRoutine
;
3338 // If we (FS) acquired locks, transition the lock owners to an object, since
3339 // when we return this thread could go away before request completion, and
3340 // the resource package may otherwise try to boost priority, etc.
3343 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TOP_LEVEL
)) {
3345 NT_ASSERT( IrpContext
->IoContext
->ResourceThreadId
== (ERESOURCE_THREAD
)PsGetCurrentThread() );
3347 IrpContext
->IoContext
->ResourceThreadId
= ((ULONG_PTR
)IrpContext
->IoContext
) | 3;
3349 ExSetResourceOwnerPointer( IrpContext
->IoContext
->Resource
,
3350 (PVOID
)IrpContext
->IoContext
->ResourceThreadId
);
3355 // Set up the completion routine address in our stack frame.
3358 IoSetCompletionRoutine( IrpContext
->Irp
,
3360 IrpContext
->IoContext
,
3366 // Setup the next IRP stack location in the associated Irp for the disk
3367 // driver beneath us.
3370 IrpSp
= IoGetNextIrpStackLocation( IrpContext
->Irp
);
3373 // Setup the Stack location to do a read from the disk driver.
3376 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
3377 IrpSp
->Parameters
.Read
.Length
= Run
->DiskByteCount
;
3378 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Run
->DiskOffset
;
3381 // Issue the Io request
3385 // If IoCallDriver returns an error, it has completed the Irp
3386 // and the error will be caught by our completion routines
3387 // and dealt with as a normal IO error.
3390 (VOID
)IoCallDriver( IrpContext
->Vcb
->TargetDeviceObject
, IrpContext
->Irp
);
3395 // Local support routine
3400 _In_ PIRP_CONTEXT IrpContext
3405 Routine Description:
3407 This routine waits for one or more previously started I/O requests
3408 from the above routines, by simply waiting on the event.
3422 (VOID
)KeWaitForSingleObject( &IrpContext
->IoContext
->SyncEvent
,
3428 KeClearEvent( &IrpContext
->IoContext
->SyncEvent
);
3433 // Local support routine
3437 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3438 CdMultiSyncCompletionRoutine (
3439 PDEVICE_OBJECT DeviceObject
,
3446 Routine Description:
3448 This is the completion routine for all synchronous reads
3449 started via CdMultipleAsynch.
3451 The completion routine has has the following responsibilities:
3453 If the individual request was completed with an error, then
3454 this completion routine must see if this is the first error
3455 and remember the error status in the Context.
3457 If the IrpCount goes to 1, then it sets the event in the Context
3458 parameter to signal the caller that all of the asynch requests
3463 DeviceObject - Pointer to the file system device object.
3465 Irp - Pointer to the associated Irp which is being completed. (This
3466 Irp will no longer be accessible after this routine returns.)
3468 Context - The context parameter which was specified for all of
3469 the multiple asynch I/O requests for this MasterIrp.
3473 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3474 immediately complete the Master Irp without being in a race condition
3475 with the IoCompleteRequest thread trying to decrement the IrpCount in
3481 PCD_IO_CONTEXT IoContext
= Context
;
3482 _Analysis_assume_(Context
!= NULL
);
3484 AssertVerifyDeviceIrp( Irp
);
3487 // If we got an error (or verify required), remember it in the Irp
3490 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3492 InterlockedExchange( &IoContext
->Status
, Irp
->IoStatus
.Status
);
3493 IoContext
->MasterIrp
->IoStatus
.Information
= 0;
3497 // We must do this here since IoCompleteRequest won't get a chance
3498 // on this associated Irp.
3501 IoFreeMdl( Irp
->MdlAddress
);
3504 if (InterlockedDecrement( &IoContext
->IrpCount
) == 0) {
3507 // Update the Master Irp with any error status from the associated Irps.
3510 IoContext
->MasterIrp
->IoStatus
.Status
= IoContext
->Status
;
3511 KeSetEvent( &IoContext
->SyncEvent
, 0, FALSE
);
3514 UNREFERENCED_PARAMETER( DeviceObject
);
3516 return STATUS_MORE_PROCESSING_REQUIRED
;
3521 // Local support routine
3525 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3526 CdMultiAsyncCompletionRoutine (
3527 PDEVICE_OBJECT DeviceObject
,
3534 Routine Description:
3536 This is the completion routine for all asynchronous reads
3537 started via CdMultipleAsynch.
3539 The completion routine has has the following responsibilities:
3541 If the individual request was completed with an error, then
3542 this completion routine must see if this is the first error
3543 and remember the error status in the Context.
3547 DeviceObject - Pointer to the file system device object.
3549 Irp - Pointer to the associated Irp which is being completed. (This
3550 Irp will no longer be accessible after this routine returns.)
3552 Context - The context parameter which was specified for all of
3553 the multiple asynch I/O requests for this MasterIrp.
3557 Currently always returns STATUS_SUCCESS.
3562 PCD_IO_CONTEXT IoContext
= Context
;
3563 _Analysis_assume_(Context
!= NULL
);
3564 AssertVerifyDeviceIrp( Irp
);
3566 UNREFERENCED_PARAMETER( DeviceObject
);
3569 // If we got an error (or verify required), remember it in the Irp
3572 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3574 InterlockedExchange( &IoContext
->Status
, Irp
->IoStatus
.Status
);
3578 // Decrement IrpCount and see if it goes to zero.
3581 if (InterlockedDecrement( &IoContext
->IrpCount
) == 0) {
3584 // Mark the master Irp pending
3587 IoMarkIrpPending( IoContext
->MasterIrp
);
3590 // Update the Master Irp with any error status from the associated Irps.
3593 IoContext
->MasterIrp
->IoStatus
.Status
= IoContext
->Status
;
3596 // Update the information field with the correct value.
3599 IoContext
->MasterIrp
->IoStatus
.Information
= 0;
3601 if (NT_SUCCESS( IoContext
->MasterIrp
->IoStatus
.Status
)) {
3603 IoContext
->MasterIrp
->IoStatus
.Information
= IoContext
->RequestedByteCount
;
3607 // Now release the resource
3610 _Analysis_assume_lock_held_(*IoContext
->Resource
);
3611 ExReleaseResourceForThreadLite( IoContext
->Resource
, IoContext
->ResourceThreadId
);
3614 // and finally, free the context record.
3617 CdFreeIoContext( IoContext
);
3620 // Return success in this case.
3623 return STATUS_SUCCESS
;
3628 // We need to cleanup the associated Irp and its Mdl.
3631 IoFreeMdl( Irp
->MdlAddress
);
3634 return STATUS_MORE_PROCESSING_REQUIRED
;
3641 // Local support routine
3645 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3646 CdSingleSyncCompletionRoutine (
3647 PDEVICE_OBJECT DeviceObject
,
3654 Routine Description:
3656 This is the completion routine for all reads started via CdSingleAsynch.
3658 The completion routine has has the following responsibilities:
3660 It sets the event in the Context parameter to signal the caller
3661 that all of the asynch requests are done.
3665 DeviceObject - Pointer to the file system device object.
3667 Irp - Pointer to the Irp for this request. (This Irp will no longer
3668 be accessible after this routine returns.)
3670 Context - The context parameter which was specified in the call to
3675 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3676 immediately complete the Master Irp without being in a race condition
3677 with the IoCompleteRequest thread trying to decrement the IrpCount in
3683 _Analysis_assume_(Context
!= NULL
);
3685 UNREFERENCED_PARAMETER( DeviceObject
);
3687 AssertVerifyDeviceIrp( Irp
);
3690 // Store the correct information field into the Irp.
3693 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3695 Irp
->IoStatus
.Information
= 0;
3698 KeSetEvent( &((PCD_IO_CONTEXT
)Context
)->SyncEvent
, 0, FALSE
);
3700 return STATUS_MORE_PROCESSING_REQUIRED
;
3705 // Local support routine
3709 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3710 CdSingleAsyncCompletionRoutine (
3711 PDEVICE_OBJECT DeviceObject
,
3718 Routine Description:
3720 This is the completion routine for all asynchronous reads
3721 started via CdSingleAsynch.
3725 DeviceObject - Pointer to the file system device object.
3727 Irp - Pointer to the Irp for this request. (This Irp will no longer
3728 be accessible after this routine returns.)
3730 Context - The context parameter which was specified in the call to
3735 Currently always returns STATUS_SUCCESS.
3740 PCD_IO_CONTEXT IoContext
= Context
;
3742 UNREFERENCED_PARAMETER( DeviceObject
);
3744 _Analysis_assume_(IoContext
!= NULL
);
3745 AssertVerifyDeviceIrp( Irp
);
3748 // Update the information field with the correct value for bytes read.
3751 Irp
->IoStatus
.Information
= 0;
3753 if (NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3755 Irp
->IoStatus
.Information
= IoContext
->RequestedByteCount
;
3759 // Mark the Irp pending
3762 IoMarkIrpPending( Irp
);
3765 // Now release the resource
3768 _Analysis_assume_lock_held_(*IoContext
->Resource
);
3769 ExReleaseResourceForThreadLite( IoContext
->Resource
, IoContext
->ResourceThreadId
);
3772 // and finally, free the context record.
3775 CdFreeIoContext( IoContext
);
3776 return STATUS_SUCCESS
;
3782 // Local support routine
3785 _When_(SafeNodeType(Fcb
) != CDFS_NTC_FCB_PATH_TABLE
&& StartingOffset
== 0, _At_(ByteCount
, _In_range_(>=, CdAudioDirentSize
+ sizeof(RAW_DIRENT
))))
3786 _When_(SafeNodeType(Fcb
) != CDFS_NTC_FCB_PATH_TABLE
&& StartingOffset
!= 0, _At_(ByteCount
, _In_range_(>=, CdAudioDirentSize
+ SECTOR_SIZE
)))
3788 CdReadAudioSystemFile (
3789 _In_ PIRP_CONTEXT IrpContext
,
3791 _In_ LONGLONG StartingOffset
,
3792 _In_
_In_range_(>=, CdAudioDirentSize
) ULONG ByteCount
,
3793 _Out_writes_bytes_(ByteCount
) PVOID SystemBuffer
3798 Routine Description:
3800 This routine is called to read the pseudo root directory and path
3801 table for a music disk. We build the individual elements on the
3802 stack and copy into the cache buffer.
3806 Fcb - Fcb representing the file to read.
3808 StartingOffset - Logical offset in the file to read from.
3810 ByteCount - Number of bytes to read.
3812 SystemBuffer - Pointer to buffer to fill in. This will always be page
3822 PRAW_PATH_ISO RawPath
;
3823 PRAW_DIRENT RawDirent
;
3830 PTRACK_DATA ThisTrack
;
3832 LONGLONG CurrentOffset
;
3834 PVOID CurrentSector
;
3836 PSYSTEM_USE_XA SystemUse
;
3840 UCHAR LocalBuffer
[FIELD_OFFSET( RAW_DIRENT
, FileId
) + 12];
3845 // If this is the path table then we just need a single entry.
3848 if (SafeNodeType( Fcb
) == CDFS_NTC_FCB_PATH_TABLE
) {
3851 // Sanity check that the offset is zero.
3854 NT_ASSERT( StartingOffset
== 0 );
3857 // Store a pseudo path entry in our local buffer.
3860 RawPath
= (PRAW_PATH_ISO
) LocalBuffer
;
3862 RtlZeroMemory( RawPath
, sizeof( LocalBuffer
));
3864 RawPath
->DirIdLen
= 1;
3865 RawPath
->ParentNum
= 1;
3866 RawPath
->DirId
[0] = '\0';
3869 // Now copy to the user's buffer.
3872 BytesToCopy
= FIELD_OFFSET( RAW_PATH_ISO
, DirId
) + 2;
3874 if (BytesToCopy
> ByteCount
) {
3876 BytesToCopy
= ByteCount
;
3879 RtlCopyMemory( SystemBuffer
,
3884 // We need to deal with the multiple sector case for the root directory.
3890 // Initialize the first track to return to our caller.
3896 // If the offset is zero then store the entries for the self and parent
3900 if (StartingOffset
== 0) {
3902 RawDirent
= SystemBuffer
;
3905 // Clear all of the fields initially.
3908 RtlZeroMemory( RawDirent
, FIELD_OFFSET( RAW_DIRENT
, FileId
));
3911 // Now fill in the interesting fields.
3914 RawDirent
->DirLen
= FIELD_OFFSET( RAW_DIRENT
, FileId
) + 1;
3915 RawDirent
->FileIdLen
= 1;
3916 RawDirent
->FileId
[0] = '\0';
3917 SetFlag( RawDirent
->FlagsISO
, CD_ATTRIBUTE_DIRECTORY
);
3920 // Set the time stamp to be Jan 1, 1995
3923 RawDirent
->RecordTime
[0] = 95;
3924 RawDirent
->RecordTime
[1] = 1;
3925 RawDirent
->RecordTime
[2] = 1;
3927 SectorOffset
= RawDirent
->DirLen
;
3929 RawDirent
= Add2Ptr( RawDirent
, SectorOffset
, PRAW_DIRENT
);
3932 // Clear all of the fields initially.
3935 RtlZeroMemory( RawDirent
, FIELD_OFFSET( RAW_DIRENT
, FileId
));
3938 // Now fill in the interesting fields.
3941 RawDirent
->DirLen
= FIELD_OFFSET( RAW_DIRENT
, FileId
) + 1;
3942 RawDirent
->FileIdLen
= 1;
3943 RawDirent
->FileId
[0] = '\1';
3944 SetFlag( RawDirent
->FlagsISO
, CD_ATTRIBUTE_DIRECTORY
);
3947 // Set the time stamp to be Jan 1, 1995
3950 RawDirent
->RecordTime
[0] = 95;
3951 RawDirent
->RecordTime
[1] = 1;
3952 RawDirent
->RecordTime
[2] = 1;
3954 SectorOffset
+= RawDirent
->DirLen
;
3958 // Otherwise compute the starting track to write to the buffer.
3964 // Count the tracks in each preceding sector.
3971 CurrentTrack
+= CdAudioDirentsPerSector
;
3972 CurrentOffset
+= SECTOR_SIZE
;
3974 } while (CurrentOffset
< StartingOffset
);
3977 // Bias the track count to reflect the two default entries.
3987 // We now know the first track to return as well as where we are in
3988 // the current sector. We will walk through sector by sector adding
3989 // the entries for the separate tracks in the TOC. We will zero
3990 // any sectors or partial sectors without data.
3993 CurrentSector
= SystemBuffer
;
3994 BytesToCopy
= SECTOR_SIZE
;
3997 // Loop for each sector.
4003 // Add entries until we reach our threshold for each sector.
4009 // If we are beyond the entries in the TOC then exit.
4012 if (CurrentTrack
>= IrpContext
->Vcb
->TrackCount
) {
4017 ThisTrack
= &IrpContext
->Vcb
->CdromToc
->TrackData
[CurrentTrack
];
4020 // Point to the current position in the buffer.
4023 RawDirent
= Add2Ptr( CurrentSector
, SectorOffset
, PRAW_DIRENT
);
4026 // Clear all of the fields initially.
4029 RtlZeroMemory( RawDirent
, CdAudioDirentSize
);
4032 // Now fill in the interesting fields.
4035 RawDirent
->DirLen
= (UCHAR
) CdAudioDirentSize
;
4036 RawDirent
->FileIdLen
= CdAudioFileNameLength
;
4038 RtlCopyMemory( RawDirent
->FileId
,
4040 CdAudioFileNameLength
);
4043 // Set the time stamp to be Jan 1, 1995 00:00
4046 RawDirent
->RecordTime
[0] = 95;
4047 RawDirent
->RecordTime
[1] = 1;
4048 RawDirent
->RecordTime
[2] = 1;
4051 // Put the track number into the file name.
4054 TrackTens
= TrackOnes
= ThisTrack
->TrackNumber
;
4056 TrackOnes
= (TrackOnes
% 10) + '0';
4059 TrackTens
= (TrackTens
% 10) + '0';
4061 RawDirent
->FileId
[AUDIO_NAME_TENS_OFFSET
] = TrackTens
;
4062 RawDirent
->FileId
[AUDIO_NAME_ONES_OFFSET
] = TrackOnes
;
4064 SystemUse
= Add2Ptr( RawDirent
, CdAudioSystemUseOffset
, PSYSTEM_USE_XA
);
4066 SystemUse
->Attributes
= SYSTEM_USE_XA_DA
;
4067 SystemUse
->Signature
= SYSTEM_XA_SIGNATURE
;
4070 // Store the track number as the file number.
4073 SystemUse
->FileNumber
= (UCHAR
) CurrentTrack
;
4076 SectorOffset
+= CdAudioDirentSize
;
4079 } while (EntryCount
< CdAudioDirentsPerSector
);
4082 // Zero the remaining portion of this buffer.
4085 RtlZeroMemory( Add2Ptr( CurrentSector
, SectorOffset
, PVOID
),
4086 SECTOR_SIZE
- SectorOffset
);
4089 // Prepare for the next sector.
4093 BytesToCopy
+= SECTOR_SIZE
;
4095 CurrentSector
= Add2Ptr( CurrentSector
, SECTOR_SIZE
, PVOID
);
4097 } while (BytesToCopy
<= ByteCount
);
4105 CdHijackIrpAndFlushDevice (
4106 _In_ PIRP_CONTEXT IrpContext
,
4108 _In_ PDEVICE_OBJECT TargetDeviceObject
4113 Routine Description:
4115 This routine is called when we need to send a flush to a device but
4116 we don't have a flush Irp. What this routine does is make a copy
4117 of its current Irp stack location, but changes the Irp Major code
4118 to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
4119 the knees in the completion routine, fix it up and return to the
4120 user as if nothing had happened.
4124 Irp - The Irp to hijack
4126 TargetDeviceObject - The device to send the request to.
4130 NTSTATUS - The Status from the flush in case anybody cares.
4137 PIO_STACK_LOCATION NextIrpSp
;
4141 UNREFERENCED_PARAMETER( IrpContext
);
4144 // Get the next stack location, and copy over the stack location
4147 NextIrpSp
= IoGetNextIrpStackLocation( Irp
);
4149 *NextIrpSp
= *IoGetCurrentIrpStackLocation( Irp
);
4151 NextIrpSp
->MajorFunction
= IRP_MJ_FLUSH_BUFFERS
;
4152 NextIrpSp
->MinorFunction
= 0;
4155 // Set up the completion routine
4158 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
4160 IoSetCompletionRoutine( Irp
,
4161 CdSyncCompletionRoutine
,
4168 // Send the request.
4171 Status
= IoCallDriver( TargetDeviceObject
, Irp
);
4173 if (Status
== STATUS_PENDING
) {
4175 (VOID
)KeWaitForSingleObject( &Event
, Executive
, KernelMode
, FALSE
, NULL
);
4177 Status
= Irp
->IoStatus
.Status
;
4181 // If the driver doesn't support flushes, return SUCCESS.
4184 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) {
4186 Status
= STATUS_SUCCESS
;
4189 Irp
->IoStatus
.Status
= 0;
4190 Irp
->IoStatus
.Information
= 0;