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
104 IN PIRP_CONTEXT IrpContext
,
108 IN ULONG UserBufferOffset
,
109 IN LONGLONG StartingOffset
,
113 IN PULONG ThisByteCount
118 IN PIRP_CONTEXT IrpContext
,
122 IN ULONG UserBufferOffset
,
123 IN LONGLONG StartingOffset
,
127 IN PULONG ThisByteCount
132 IN PIRP_CONTEXT IrpContext
,
135 IN BOOLEAN FinalCleanup
,
136 IN BOOLEAN SaveXABuffer
141 IN PIRP_CONTEXT IrpContext
,
148 IN PIRP_CONTEXT IrpContext
,
151 IN PRAW_READ_INFO RawReads
,
152 IN TRACK_MODE_TYPE TrackMode
157 IN PIRP_CONTEXT IrpContext
,
158 IN LONGLONG ByteOffset
,
164 IN PIRP_CONTEXT IrpContext
168 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
169 CdMultiSyncCompletionRoutine (
170 IN PDEVICE_OBJECT DeviceObject
,
176 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
177 CdMultiAsyncCompletionRoutine (
178 IN PDEVICE_OBJECT DeviceObject
,
184 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
185 CdSingleSyncCompletionRoutine (
186 IN PDEVICE_OBJECT DeviceObject
,
192 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
193 CdSingleAsyncCompletionRoutine (
194 IN PDEVICE_OBJECT DeviceObject
,
200 CdReadAudioSystemFile (
201 IN PIRP_CONTEXT IrpContext
,
203 IN LONGLONG StartingOffset
,
205 IN PVOID SystemBuffer
209 #pragma alloc_text(PAGE, CdCreateUserMdl)
210 #pragma alloc_text(PAGE, CdMultipleAsync)
211 #pragma alloc_text(PAGE, CdMultipleXAAsync)
212 #pragma alloc_text(PAGE, CdNonCachedRead)
213 #pragma alloc_text(PAGE, CdNonCachedXARead)
214 #pragma alloc_text(PAGE, CdFinishBuffers)
215 #pragma alloc_text(PAGE, CdPerformDevIoCtrl)
216 #pragma alloc_text(PAGE, CdPrepareBuffers)
217 #pragma alloc_text(PAGE, CdReadAudioSystemFile)
218 #pragma alloc_text(PAGE, CdReadSectors)
219 #pragma alloc_text(PAGE, CdSingleAsync)
220 #pragma alloc_text(PAGE, CdWaitSync)
234 This routine converts FCB XA file type flags to the track mode
235 used by the device drivers.
239 Fcb - Fcb representing the file to read.
243 TrackMode of the file represented by the Fcb.
247 ASSERT( FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
|
248 FCB_STATE_MODE2_FILE
|
249 FCB_STATE_DA_FILE
));
251 if (FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
)) {
255 } else if (FlagOn( Fcb
->FcbState
, FCB_STATE_DA_FILE
)) {
262 // FCB_STATE_MODE2_FILE
271 IN PIRP_CONTEXT IrpContext
,
273 IN LONGLONG StartingOffset
,
281 This routine performs the non-cached reads to 'cooked' sectors (2048 bytes
282 per sector). This is done by performing the following in a loop.
284 Fill in the IoRuns array for the next block of Io.
285 Send the Io to the device.
286 Perform any cleanup on the Io runs array.
288 We will not do async Io to any request that generates non-aligned Io.
289 Also we will not perform async Io if it will exceed the size of our
290 IoRuns array. These should be the unusual cases but we will raise
291 or return CANT_WAIT in this routine if we detect this case.
295 Fcb - Fcb representing the file to read.
297 StartingOffset - Logical offset in the file to read from.
299 ByteCount - Number of bytes to read.
303 NTSTATUS - Status indicating the result of the operation.
308 NTSTATUS Status
= STATUS_SUCCESS
;
310 IO_RUN IoRuns
[MAX_PARALLEL_IOS
];
312 ULONG CleanupRunCount
= 0;
315 ULONG UserBufferOffset
= 0;
316 LONGLONG CurrentOffset
= StartingOffset
;
317 ULONG RemainingByteCount
= ByteCount
;
321 BOOLEAN FlushIoBuffers
= FALSE
;
322 BOOLEAN FirstPass
= TRUE
;
327 // We want to make sure the user's buffer is locked in all cases.
330 if (IrpContext
->Irp
->MdlAddress
== NULL
) {
332 CdCreateUserMdl( IrpContext
, ByteCount
, TRUE
);
335 CdMapUserBuffer( IrpContext
, &UserBuffer
);
338 // Special case the root directory and path table for a music volume.
341 if (FlagOn( Fcb
->Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
) &&
342 ((SafeNodeType( Fcb
) == CDFS_NTC_FCB_INDEX
) ||
343 (SafeNodeType( Fcb
) == CDFS_NTC_FCB_PATH_TABLE
))) {
345 CdReadAudioSystemFile( IrpContext
,
351 return STATUS_SUCCESS
;
355 // Use a try-finally to perform the final cleanup.
361 // Loop while there are more bytes to transfer.
367 // Call prepare buffers to set up the next entries
368 // in the IoRuns array. Remember if there are any
369 // unaligned entries. This routine will raise CANT_WAIT
370 // if there are unaligned entries for an async request.
373 RtlZeroMemory( IoRuns
, sizeof( IoRuns
));
375 Unaligned
= CdPrepareBuffers( IrpContext
,
387 RunCount
= CleanupRunCount
;
390 // If this is an async request and there aren't enough entries
391 // in the Io array then post the request.
394 if ((ThisByteCount
< RemainingByteCount
) &&
395 !FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
397 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
401 // If the entire Io is contained in a single run then
402 // we can pass the Io down to the driver. Send the driver down
403 // and wait on the result if this is synchronous.
406 if ((RunCount
== 1) && !Unaligned
&& FirstPass
) {
408 CdSingleAsync( IrpContext
,
409 IoRuns
[0].DiskOffset
,
410 IoRuns
[0].DiskByteCount
);
413 // No cleanup needed for the IoRuns array here.
419 // Wait if we are synchronous, otherwise return
422 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
424 CdWaitSync( IrpContext
);
426 Status
= IrpContext
->Irp
->IoStatus
.Status
;
429 // Our completion routine will free the Io context but
430 // we do want to return STATUS_PENDING.
435 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
436 Status
= STATUS_PENDING
;
439 try_return( NOTHING
);
443 // Otherwise we will perform multiple Io to read in the data.
446 CdMultipleAsync( IrpContext
, RunCount
, IoRuns
);
449 // If this is a synchronous request then perform any necessary
453 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
456 // Wait for the request to complete.
459 CdWaitSync( IrpContext
);
461 Status
= IrpContext
->Irp
->IoStatus
.Status
;
464 // Exit this loop if there is an error.
467 if (!NT_SUCCESS( Status
)) {
469 try_return( NOTHING
);
473 // Perform post read operations on the IoRuns if
478 CdFinishBuffers( IrpContext
, IoRuns
, RunCount
, FALSE
, FALSE
)) {
480 FlushIoBuffers
= TRUE
;
486 // Exit this loop if there are no more bytes to transfer
487 // or we have any error.
490 RemainingByteCount
-= ThisByteCount
;
491 CurrentOffset
+= ThisByteCount
;
492 UserBuffer
= Add2Ptr( UserBuffer
, ThisByteCount
, PVOID
);
493 UserBufferOffset
+= ThisByteCount
;
496 // Otherwise this is an asynchronous request. Always return
502 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
504 try_return( Status
= STATUS_PENDING
);
509 } while (RemainingByteCount
!= 0);
512 // Flush the hardware cache if we performed any copy operations.
515 if (FlushIoBuffers
) {
517 KeFlushIoBuffers( IrpContext
->Irp
->MdlAddress
, TRUE
, FALSE
);
524 // Perform final cleanup on the IoRuns if necessary.
527 if (CleanupRunCount
!= 0) {
529 CdFinishBuffers( IrpContext
, IoRuns
, CleanupRunCount
, TRUE
, FALSE
);
539 IN PIRP_CONTEXT IrpContext
,
541 IN LONGLONG StartingOffset
,
549 This routine performs the non-cached reads for 'raw' sectors (2352 bytes
550 per sector). We also prepend a hard-coded RIFF header of 44 bytes to the file.
551 All of this is already reflected in the file size.
553 We start by checking whether to prepend any portion of the RIFF header. Then we check
554 if the last raw sector read was from the beginning portion of this file, deallocating
555 that buffer if necessary. Finally we do the following in a loop.
557 Fill the IoRuns array for the next block of Io.
558 Send the Io to the device driver.
559 Perform any cleanup necessary on the IoRuns array.
561 We will not do any async request in this path. The request would have been
562 posted to a worker thread before getting to this point.
566 Fcb - Fcb representing the file to read.
568 StartingOffset - Logical offset in the file to read from.
570 ByteCount - Number of bytes to read.
574 NTSTATUS - Status indicating the result of the operation.
579 NTSTATUS Status
= STATUS_SUCCESS
;
581 RIFF_HEADER LocalRiffHeader
;
582 PRIFF_HEADER RiffHeader
;
584 RAW_READ_INFO RawReads
[MAX_PARALLEL_IOS
];
585 IO_RUN IoRuns
[MAX_PARALLEL_IOS
];
587 ULONG CleanupRunCount
= 0;
590 ULONG UserBufferOffset
= 0;
591 LONGLONG CurrentOffset
= StartingOffset
;
592 ULONG RemainingByteCount
= ByteCount
;
595 BOOLEAN TryingYellowbookMode2
= FALSE
;
597 TRACK_MODE_TYPE TrackMode
;
602 // We want to make sure the user's buffer is locked in all cases.
605 if (IrpContext
->Irp
->MdlAddress
== NULL
) {
607 CdCreateUserMdl( IrpContext
, ByteCount
, TRUE
);
611 // The byte count was rounded up to a logical sector boundary. It has
612 // nothing to do with the raw sectors on disk. Limit the remaining
613 // byte count to file size.
616 if (CurrentOffset
+ RemainingByteCount
> Fcb
->FileSize
.QuadPart
) {
618 RemainingByteCount
= (ULONG
) (Fcb
->FileSize
.QuadPart
- CurrentOffset
);
621 CdMapUserBuffer( IrpContext
, &UserBuffer
);
624 // Use a try-finally to perform the final cleanup.
630 // If the initial offset lies within the RIFF header then copy the
631 // necessary bytes to the user's buffer.
634 if (CurrentOffset
< sizeof( RIFF_HEADER
)) {
637 // Copy the appropriate RIFF header.
640 if (FlagOn( Fcb
->FcbState
, FCB_STATE_DA_FILE
)) {
643 // Create the pseudo entries for a music disk.
646 if (FlagOn( Fcb
->Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
648 PAUDIO_PLAY_HEADER AudioPlayHeader
;
649 PTRACK_DATA TrackData
;
652 AudioPlayHeader
= (PAUDIO_PLAY_HEADER
) &LocalRiffHeader
;
653 TrackData
= &Fcb
->Vcb
->CdromToc
->TrackData
[Fcb
->XAFileNumber
];
656 // Copy the data header into our local buffer.
659 RtlCopyMemory( AudioPlayHeader
,
661 sizeof( AUDIO_PLAY_HEADER
));
664 // Copy the serial number into the Id field. Also
665 // the track number in the TOC.
668 AudioPlayHeader
->DiskID
= Fcb
->Vcb
->Vpb
->SerialNumber
;
669 AudioPlayHeader
->TrackNumber
= TrackData
->TrackNumber
;
672 // TOC contains MSF (Minute/Second/Frame) addresses. This is very
673 // arcane, and we wind up having to bias around by the size of the
674 // leadins and other such silliness to find real live sector addrs.
676 // One frame == One sector.
677 // One second == 75 frames (winds up being a 44.1khz sample)
681 // Fill in the address and length fields.
684 AudioPlayHeader
->TrackAddress
[2] = TrackData
->Address
[1];
685 AudioPlayHeader
->TrackAddress
[1] = TrackData
->Address
[2];
686 AudioPlayHeader
->TrackAddress
[0] = TrackData
->Address
[3];
688 AudioPlayHeader
->StartingSector
= TrackData
->Address
[3];
689 AudioPlayHeader
->StartingSector
+= (TrackData
->Address
[2] * 75);
690 AudioPlayHeader
->StartingSector
+= (TrackData
->Address
[1] * 60 * 75);
693 // Subtract 2 seconds for the block number.
696 AudioPlayHeader
->StartingSector
-= 150;
699 // Go to the next track and find the starting point.
702 TrackData
= &Fcb
->Vcb
->CdromToc
->TrackData
[Fcb
->XAFileNumber
+ 1];
704 AudioPlayHeader
->SectorCount
= TrackData
->Address
[3];
705 AudioPlayHeader
->SectorCount
+= (TrackData
->Address
[2] * 75);
706 AudioPlayHeader
->SectorCount
+= (TrackData
->Address
[1] * 60 * 75);
709 // Bias the sector count by 2 seconds.
710 // Check that the offset is at least two seconds.
713 if (AudioPlayHeader
->SectorCount
< 150) {
715 AudioPlayHeader
->SectorCount
= 0;
719 AudioPlayHeader
->SectorCount
-= 150;
723 // Now compute the difference. If there is an error then use
727 if (AudioPlayHeader
->SectorCount
< AudioPlayHeader
->StartingSector
) {
729 AudioPlayHeader
->SectorCount
= 0;
733 AudioPlayHeader
->SectorCount
-= AudioPlayHeader
->StartingSector
;
737 // Use the sector count to determine the MSF length.
740 SectorCount
= AudioPlayHeader
->SectorCount
;
742 AudioPlayHeader
->TrackLength
[0] = (UCHAR
) (SectorCount
% 75);
745 AudioPlayHeader
->TrackLength
[1] = (UCHAR
) (SectorCount
% 60);
748 AudioPlayHeader
->TrackLength
[2] = (UCHAR
) (SectorCount
% 60);
750 ThisByteCount
= sizeof( RIFF_HEADER
) - (ULONG
) CurrentOffset
;
752 RtlCopyMemory( UserBuffer
,
753 Add2Ptr( AudioPlayHeader
,
754 sizeof( RIFF_HEADER
) - ThisByteCount
,
765 // The WAVE header format is actually much closer to an audio play
766 // header in format but we only need to modify the filesize fields.
769 RiffHeader
= &LocalRiffHeader
;
772 // Copy the data header into our local buffer and add the file size to it.
775 RtlCopyMemory( RiffHeader
,
776 CdXAAudioPhileHeader
,
777 sizeof( RIFF_HEADER
));
779 RiffHeader
->ChunkSize
+= Fcb
->FileSize
.LowPart
;
780 RiffHeader
->RawSectors
+= Fcb
->FileSize
.LowPart
;
782 ThisByteCount
= sizeof( RIFF_HEADER
) - (ULONG
) CurrentOffset
;
783 RtlCopyMemory( UserBuffer
,
785 sizeof( RIFF_HEADER
) - ThisByteCount
,
796 ASSERT( FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2_FILE
| FCB_STATE_MODE2FORM2_FILE
));
798 RiffHeader
= &LocalRiffHeader
;
801 // Copy the data header into our local buffer and add the file size to it.
804 RtlCopyMemory( RiffHeader
,
806 sizeof( RIFF_HEADER
));
808 RiffHeader
->ChunkSize
+= Fcb
->FileSize
.LowPart
;
809 RiffHeader
->RawSectors
+= Fcb
->FileSize
.LowPart
;
811 RiffHeader
->Attributes
= (USHORT
) Fcb
->XAAttributes
;
812 RiffHeader
->FileNumber
= (UCHAR
) Fcb
->XAFileNumber
;
814 ThisByteCount
= sizeof( RIFF_HEADER
) - (ULONG
) CurrentOffset
;
815 RtlCopyMemory( UserBuffer
,
817 sizeof( RIFF_HEADER
) - ThisByteCount
,
823 // Adjust the starting offset and byte count to reflect that
824 // we copied over the RIFF bytes.
827 UserBuffer
= Add2Ptr( UserBuffer
, ThisByteCount
, PVOID
);
828 UserBufferOffset
+= ThisByteCount
;
829 CurrentOffset
+= ThisByteCount
;
830 RemainingByteCount
-= ThisByteCount
;
834 // Set up the appropriate trackmode
837 TrackMode
= CdFileTrackMode(Fcb
);
840 // Loop while there are more bytes to transfer.
843 while (RemainingByteCount
!= 0) {
846 // Call prepare buffers to set up the next entries
847 // in the IoRuns array. Remember if there are any
848 // unaligned entries. If we're just retrying the previous
849 // runs with a different track mode, then don't do anything here.
852 if (!TryingYellowbookMode2
) {
854 RtlZeroMemory( IoRuns
, sizeof( IoRuns
));
855 RtlZeroMemory( RawReads
, sizeof( RawReads
));
857 CdPrepareXABuffers( IrpContext
,
870 // Perform multiple Io to read in the data. Note that
871 // there may be no Io to do if we were able to use an
872 // existing buffer from the Vcb.
875 if (CleanupRunCount
!= 0) {
877 RunCount
= CleanupRunCount
;
879 CdMultipleXAAsync( IrpContext
,
885 // Wait for the request to complete.
888 CdWaitSync( IrpContext
);
890 Status
= IrpContext
->Irp
->IoStatus
.Status
;
893 // Exit this loop if there is an error.
896 if (!NT_SUCCESS( Status
)) {
898 if (!TryingYellowbookMode2
&&
899 FlagOn( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
)) {
902 // There are wacky cases where someone has mastered as CD-XA
903 // but the sectors they claim are Mode2Form2 are really, according
904 // to ATAPI devices, Yellowbook Mode2. We will try once more
905 // with these. Kodak PHOTO-CD has been observed to do this.
908 TryingYellowbookMode2
= TRUE
;
909 TrackMode
= YellowMode2
;
912 // Clear our 'cumulative' error status value
915 IrpContext
->IoContext
->Status
= STATUS_SUCCESS
;
920 try_return( NOTHING
);
925 if (TryingYellowbookMode2
) {
928 // We successfully got data when we tried switching the trackmode,
929 // so change the state of the FCB to remember that.
932 SetFlag( Fcb
->FcbState
, FCB_STATE_MODE2_FILE
);
933 ClearFlag( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
);
935 TryingYellowbookMode2
= FALSE
;
939 // Perform post read operations on the IoRuns if
943 CdFinishBuffers( IrpContext
, IoRuns
, RunCount
, FALSE
, TRUE
);
947 // Adjust our loop variants.
950 RemainingByteCount
-= ThisByteCount
;
951 CurrentOffset
+= ThisByteCount
;
952 UserBuffer
= Add2Ptr( UserBuffer
, ThisByteCount
, PVOID
);
953 UserBufferOffset
+= ThisByteCount
;
957 // Always flush the hardware cache.
960 KeFlushIoBuffers( IrpContext
->Irp
->MdlAddress
, TRUE
, FALSE
);
966 // Perform final cleanup on the IoRuns if necessary.
969 if (CleanupRunCount
!= 0) {
971 CdFinishBuffers( IrpContext
, IoRuns
, CleanupRunCount
, TRUE
, FALSE
);
981 IN PIRP_CONTEXT IrpContext
,
982 IN LONGLONG StartingOffset
,
984 IN BOOLEAN ReturnError
,
986 IN PDEVICE_OBJECT TargetDeviceObject
993 This routine is called to transfer sectors from the disk to a
994 specified buffer. It is used for mount and volume verify operations.
996 This routine is synchronous, it will not return until the operation
997 is complete or until the operation fails.
999 The routine allocates an IRP and then passes this IRP to a lower
1000 level driver. Errors may occur in the allocation of this IRP or
1001 in the operation of the lower driver.
1005 StartingOffset - Logical offset on the disk to start the read. This
1006 must be on a sector boundary, no check is made here.
1008 ByteCount - Number of bytes to read. This is an integral number of
1009 2K sectors, no check is made here to confirm this.
1011 ReturnError - Indicates whether we should return TRUE or FALSE
1012 to indicate an error or raise an error condition. This only applies
1013 to the result of the IO. Any other error may cause a raise.
1015 Buffer - Buffer to transfer the disk data into.
1017 TargetDeviceObject - The device object for the volume to be read.
1021 BOOLEAN - Depending on 'RaiseOnError' flag above. TRUE if operation
1022 succeeded, FALSE otherwise.
1034 // Initialize the event.
1037 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
1040 // Attempt to allocate the IRP. If unsuccessful, raise
1041 // STATUS_INSUFFICIENT_RESOURCES.
1044 Irp
= IoBuildSynchronousFsdRequest( IRP_MJ_READ
,
1048 (PLARGE_INTEGER
) &StartingOffset
,
1050 &IrpContext
->Irp
->IoStatus
);
1054 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1058 // Ignore the change line (verify) for mount and verify requests
1061 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1064 // Send the request down to the driver. If an error occurs return
1065 // it to the caller.
1068 Status
= IoCallDriver( TargetDeviceObject
, Irp
);
1071 // If the status was STATUS_PENDING then wait on the event.
1074 if (Status
== STATUS_PENDING
) {
1076 Status
= KeWaitForSingleObject( &Event
,
1083 // On a successful wait pull the status out of the IoStatus block.
1086 if (NT_SUCCESS( Status
)) {
1088 Status
= IrpContext
->Irp
->IoStatus
.Status
;
1093 // Check whether we should raise in the error case.
1096 if (!NT_SUCCESS( Status
)) {
1100 CdNormalizeAndRaiseStatus( IrpContext
, Status
);
1104 // We don't raise, but return FALSE to indicate an error.
1110 // The operation completed successfully.
1122 IN PIRP_CONTEXT IrpContext
,
1123 IN ULONG BufferLength
,
1124 IN BOOLEAN RaiseOnError
1129 Routine Description:
1131 This routine locks the specified buffer for read access (we only write into
1132 the buffer). The file system requires this routine since it does not
1133 ask the I/O system to lock its buffers for direct I/O. This routine
1134 may only be called from the Fsd while still in the user context.
1136 This routine is only called if there is not already an Mdl.
1140 BufferLength - Length of user buffer.
1142 RaiseOnError - Indicates if our caller wants this routine to raise on
1147 NTSTATUS - Status from this routine. Error status only returned if
1148 RaiseOnError is FALSE.
1153 NTSTATUS Status
= STATUS_INSUFFICIENT_RESOURCES
;
1158 ASSERT_IRP_CONTEXT( IrpContext
);
1159 ASSERT_IRP( IrpContext
->Irp
);
1160 ASSERT( IrpContext
->Irp
->MdlAddress
== NULL
);
1163 // Allocate the Mdl, and Raise if we fail.
1166 Mdl
= IoAllocateMdl( IrpContext
->Irp
->UserBuffer
,
1175 // Now probe the buffer described by the Irp. If we get an exception,
1176 // deallocate the Mdl and return the appropriate "expected" status.
1181 MmProbeAndLockPages( Mdl
, IrpContext
->Irp
->RequestorMode
, IoWriteAccess
);
1183 Status
= STATUS_SUCCESS
;
1185 } except(EXCEPTION_EXECUTE_HANDLER
) {
1187 Status
= GetExceptionCode();
1190 IrpContext
->Irp
->MdlAddress
= NULL
;
1192 if (!FsRtlIsNtstatusExpected( Status
)) {
1194 Status
= STATUS_INVALID_USER_BUFFER
;
1200 // Check if we are to raise or return
1203 if (Status
!= STATUS_SUCCESS
) {
1207 CdRaiseStatus( IrpContext
, Status
);
1212 // Return the status code.
1220 CdPerformDevIoCtrl (
1221 IN PIRP_CONTEXT IrpContext
,
1222 IN ULONG IoControlCode
,
1223 IN PDEVICE_OBJECT Device
,
1224 OUT PVOID OutputBuffer OPTIONAL
,
1225 IN ULONG OutputBufferLength
,
1226 IN BOOLEAN InternalDeviceIoControl
,
1227 IN BOOLEAN OverrideVerify
,
1228 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
1233 Routine Description:
1235 This routine is called to perform DevIoCtrl functions internally within
1236 the filesystem. We take the status from the driver and return it to our
1241 IoControlCode - Code to send to driver.
1243 Device - This is the device to send the request to.
1245 OutPutBuffer - Pointer to output buffer.
1247 OutputBufferLength - Length of output buffer above.
1249 InternalDeviceIoControl - Indicates if this is an internal or external
1252 OverrideVerify - Indicates if we should tell the driver not to return
1253 STATUS_VERIFY_REQUIRED for mount and verify.
1255 Iosb - If specified, we return the results of the operation here.
1259 NTSTATUS - Status returned by next lower driver.
1267 IO_STATUS_BLOCK LocalIosb
;
1268 PIO_STATUS_BLOCK IosbToUse
= &LocalIosb
;
1273 // Check if the user gave us an Iosb.
1276 if (ARGUMENT_PRESENT( Iosb
)) {
1281 IosbToUse
->Status
= 0;
1282 IosbToUse
->Information
= 0;
1284 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
1286 Irp
= IoBuildDeviceIoControlRequest( IoControlCode
,
1292 InternalDeviceIoControl
,
1298 return STATUS_INSUFFICIENT_RESOURCES
;
1301 if (OverrideVerify
) {
1303 SetFlag( IoGetNextIrpStackLocation( Irp
)->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1306 Status
= IoCallDriver( Device
, Irp
);
1309 // We check for device not ready by first checking Status
1310 // and then if status pending was returned, the Iosb status
1314 if (Status
== STATUS_PENDING
) {
1316 (VOID
) KeWaitForSingleObject( &Event
,
1320 (PLARGE_INTEGER
)NULL
);
1322 Status
= IosbToUse
->Status
;
1325 ASSERT( !(OverrideVerify
&& (STATUS_VERIFY_REQUIRED
== Status
)));
1332 // Local support routine
1337 IN PIRP_CONTEXT IrpContext
,
1340 IN PVOID UserBuffer
,
1341 IN ULONG UserBufferOffset
,
1342 IN LONGLONG StartingOffset
,
1346 IN PULONG ThisByteCount
1351 Routine Description:
1353 This routine is the worker routine which looks up each run of an IO
1354 request and stores an entry for it in the IoRuns array. If the run
1355 begins on an unaligned disk boundary then we will allocate a buffer
1356 and Mdl for the unaligned portion and put it in the IoRuns entry.
1358 This routine will raise CANT_WAIT if an unaligned transfer is encountered
1359 and this request can't wait.
1363 Irp - Originating Irp for this request.
1365 Fcb - This is the Fcb for this data stream. It may be a file, directory,
1366 path table or the volume file.
1368 UserBuffer - Current position in the user's buffer.
1370 UserBufferOffset - Offset from the start of the original user buffer.
1372 StartingOffset - Offset in the stream to begin the read.
1374 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1375 to this point. We will stop early if we exceed the maximum number
1376 of parallel Ios we support.
1378 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1379 this routine is called.
1381 RunCount - Number of entries in the IoRuns array filled here.
1383 ThisByteCount - Number of bytes described by the IoRun entries. Will
1384 not exceed the ByteCount passed in.
1388 BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
1389 this is synchronous). FALSE otherwise.
1394 BOOLEAN FoundUnaligned
= FALSE
;
1395 PIO_RUN ThisIoRun
= IoRuns
;
1398 // Following indicate where we are in the current transfer. Current
1399 // position in the file and number of bytes yet to transfer from
1403 ULONG RemainingByteCount
= ByteCount
;
1404 LONGLONG CurrentFileOffset
= StartingOffset
;
1407 // Following indicate the state of the user's buffer. We have
1408 // the destination of the next transfer and its offset in the
1409 // buffer. We also have the next available position in the buffer
1410 // available for a scratch buffer. We will align this up to a sector
1414 PVOID CurrentUserBuffer
= UserBuffer
;
1415 ULONG CurrentUserBufferOffset
= UserBufferOffset
;
1417 PVOID ScratchUserBuffer
= UserBuffer
;
1418 ULONG ScratchUserBufferOffset
= UserBufferOffset
;
1421 // The following is the next contiguous bytes on the disk to
1422 // transfer. Read from the allocation package.
1425 LONGLONG DiskOffset
;
1426 ULONG CurrentByteCount
;
1431 // Initialize the RunCount and ByteCount.
1438 // Loop while there are more bytes to process or there are
1439 // available entries in the IoRun array.
1447 // Initialize the current position in the IoRuns array.
1448 // Find the user's buffer for this portion of the transfer.
1451 ThisIoRun
->UserBuffer
= CurrentUserBuffer
;
1454 // Find the allocation information for the current offset in the
1458 CdLookupAllocation( IrpContext
,
1462 &CurrentByteCount
);
1465 // Limit ourselves to the data requested.
1468 if (CurrentByteCount
> RemainingByteCount
) {
1470 CurrentByteCount
= RemainingByteCount
;
1474 // Handle the case where this is an unaligned transfer. The
1475 // following must all be true for this to be an aligned transfer.
1477 // Disk offset on a 2048 byte boundary (Start of transfer)
1479 // Byte count is a multiple of 2048 (Length of transfer)
1481 // Current buffer offset is also on a 2048 byte boundary.
1483 // If the ByteCount is at least one sector then do the
1484 // unaligned transfer only for the tail. We can use the
1485 // user's buffer for the aligned portion.
1488 if (FlagOn( (ULONG
) DiskOffset
, SECTOR_MASK
) ||
1489 FlagOn( CurrentUserBufferOffset
, SECTOR_MASK
) ||
1490 (FlagOn( (ULONG
) CurrentByteCount
, SECTOR_MASK
) &&
1491 (CurrentByteCount
< SECTOR_SIZE
))) {
1494 // If we can't wait then raise.
1497 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
1499 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
1503 // Remember the offset and the number of bytes out of
1504 // the transfer buffer to copy into the user's buffer.
1505 // We will truncate the current read to end on a sector
1509 ThisIoRun
->TransferBufferOffset
= SectorOffset( DiskOffset
);
1512 // Make sure this transfer ends on a sector boundary.
1515 ThisIoRun
->DiskOffset
= LlSectorTruncate( DiskOffset
);
1518 // Check if we can use a free portion of the user's buffer.
1519 // If we can copy the bytes to an earlier portion of the
1520 // buffer then read into that location and slide the bytes
1523 // We can use the user's buffer if:
1525 // The temporary location in the buffer is before the
1526 // final destination.
1528 // There is at least one sector of data to read.
1531 if ((ScratchUserBufferOffset
+ ThisIoRun
->TransferBufferOffset
< CurrentUserBufferOffset
) &&
1532 (ThisIoRun
->TransferBufferOffset
+ CurrentByteCount
>= SECTOR_SIZE
)) {
1534 ThisIoRun
->DiskByteCount
= SectorTruncate( ThisIoRun
->TransferBufferOffset
+ CurrentByteCount
);
1535 CurrentByteCount
= ThisIoRun
->DiskByteCount
- ThisIoRun
->TransferBufferOffset
;
1536 ThisIoRun
->TransferByteCount
= CurrentByteCount
;
1539 // Point to the user's buffer and Mdl for this transfer.
1542 ThisIoRun
->TransferBuffer
= ScratchUserBuffer
;
1543 ThisIoRun
->TransferMdl
= Irp
->MdlAddress
;
1544 ThisIoRun
->TransferVirtualAddress
= Add2Ptr( Irp
->UserBuffer
,
1545 ScratchUserBufferOffset
,
1548 ScratchUserBuffer
= Add2Ptr( ScratchUserBuffer
,
1549 ThisIoRun
->DiskByteCount
,
1552 ScratchUserBufferOffset
+= ThisIoRun
->DiskByteCount
;
1555 // Otherwise we need to allocate an auxiliary buffer for the next sector.
1561 // Read up to a page containing the partial data
1564 ThisIoRun
->DiskByteCount
= SectorAlign( ThisIoRun
->TransferBufferOffset
+ CurrentByteCount
);
1566 if (ThisIoRun
->DiskByteCount
> PAGE_SIZE
) {
1568 ThisIoRun
->DiskByteCount
= PAGE_SIZE
;
1571 if (ThisIoRun
->TransferBufferOffset
+ CurrentByteCount
> ThisIoRun
->DiskByteCount
) {
1573 CurrentByteCount
= ThisIoRun
->DiskByteCount
- ThisIoRun
->TransferBufferOffset
;
1576 ThisIoRun
->TransferByteCount
= CurrentByteCount
;
1579 // Allocate a buffer for the non-aligned transfer.
1582 ThisIoRun
->TransferBuffer
= FsRtlAllocatePoolWithTag( CdNonPagedPool
, PAGE_SIZE
, TAG_IO_BUFFER
);
1585 // Allocate and build the Mdl to describe this buffer.
1588 ThisIoRun
->TransferMdl
= IoAllocateMdl( ThisIoRun
->TransferBuffer
,
1594 ThisIoRun
->TransferVirtualAddress
= ThisIoRun
->TransferBuffer
;
1596 if (ThisIoRun
->TransferMdl
== NULL
) {
1598 IrpContext
->Irp
->IoStatus
.Information
= 0;
1599 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1602 MmBuildMdlForNonPagedPool( ThisIoRun
->TransferMdl
);
1606 // Remember we found an unaligned transfer.
1609 FoundUnaligned
= TRUE
;
1612 // Otherwise we use the buffer and Mdl from the original request.
1618 // Truncate the read length to a sector-aligned value. We know
1619 // the length must be at least one sector or we wouldn't be
1623 CurrentByteCount
= SectorTruncate( CurrentByteCount
);
1626 // Read these sectors from the disk.
1629 ThisIoRun
->DiskOffset
= DiskOffset
;
1630 ThisIoRun
->DiskByteCount
= CurrentByteCount
;
1633 // Use the user's buffer and Mdl as our transfer buffer
1637 ThisIoRun
->TransferBuffer
= CurrentUserBuffer
;
1638 ThisIoRun
->TransferMdl
= Irp
->MdlAddress
;
1639 ThisIoRun
->TransferVirtualAddress
= Add2Ptr( Irp
->UserBuffer
,
1640 CurrentUserBufferOffset
,
1643 ScratchUserBuffer
= Add2Ptr( CurrentUserBuffer
,
1647 ScratchUserBufferOffset
+= CurrentByteCount
;
1651 // Update our position in the transfer and the RunCount and
1652 // ByteCount for the user.
1655 RemainingByteCount
-= CurrentByteCount
;
1658 // Break out if no more positions in the IoRuns array or
1659 // we have all of the bytes accounted for.
1662 *ThisByteCount
+= CurrentByteCount
;
1664 if ((RemainingByteCount
== 0) || (*RunCount
== MAX_PARALLEL_IOS
)) {
1670 // Update our pointers for the user's buffer.
1674 CurrentUserBuffer
= Add2Ptr( CurrentUserBuffer
, CurrentByteCount
, PVOID
);
1675 CurrentUserBufferOffset
+= CurrentByteCount
;
1676 CurrentFileOffset
+= CurrentByteCount
;
1679 return FoundUnaligned
;
1684 // Local support routine
1688 CdPrepareXABuffers (
1689 IN PIRP_CONTEXT IrpContext
,
1692 IN PVOID UserBuffer
,
1693 IN ULONG UserBufferOffset
,
1694 IN LONGLONG StartingOffset
,
1698 IN PULONG ThisByteCount
1703 Routine Description:
1705 This routine is the worker routine which looks up the individual runs
1706 of an IO request and stores an entry for it in the IoRuns array. The
1707 worker routine is for XA files where we need to convert the raw offset
1708 in the file to logical cooked sectors. We store one raw sector in
1709 the Vcb. If the current read is to that sector then we can simply copy
1710 whatever bytes are needed from that sector.
1714 Irp - Originating Irp for this request.
1716 Fcb - This is the Fcb for this data stream. It must be a data stream.
1718 UserBuffer - Current position in the user's buffer.
1720 UserBufferOffset - Offset of this buffer from the beginning of the user's
1721 buffer for the original request.
1723 StartingOffset - Offset in the stream to begin the read.
1725 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1726 to this point. We will stop early if we exceed the maximum number
1727 of parallel Ios we support.
1729 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1730 this routine is called.
1732 RunCount - Number of entries in the IoRuns array filled here.
1734 ThisByteCount - Number of bytes described by the IoRun entries. Will
1735 not exceed the ByteCount passed in.
1744 PIO_RUN ThisIoRun
= IoRuns
;
1745 BOOLEAN PerformedCopy
;
1748 // The following deal with where we are in the range of raw sectors.
1749 // Note that we will bias the input file offset by the RIFF header
1750 // to deal directly with the raw sectors.
1753 ULONG RawSectorOffset
;
1754 ULONG RemainingRawByteCount
= ByteCount
;
1755 LONGLONG CurrentRawOffset
= StartingOffset
- sizeof( RIFF_HEADER
);
1758 // The following is the offset into the cooked sectors for the file.
1761 LONGLONG CurrentCookedOffset
;
1762 ULONG RemainingCookedByteCount
;
1765 // Following indicate the state of the user's buffer. We have
1766 // the destination of the next transfer and its offset in the
1767 // buffer. We also have the next available position in the buffer
1768 // available for a scratch buffer.
1771 PVOID CurrentUserBuffer
= UserBuffer
;
1772 ULONG CurrentUserBufferOffset
= UserBufferOffset
;
1774 PVOID ScratchUserBuffer
= UserBuffer
;
1775 ULONG ScratchUserBufferOffset
= UserBufferOffset
;
1776 BOOLEAN RoundScratchBuffer
= TRUE
;
1779 // The following is the next contiguous bytes on the disk to
1780 // transfer. These are represented by cooked byte offset and length.
1781 // We also compute the number of raw bytes in the current transfer.
1784 LONGLONG DiskOffset
;
1785 ULONG CurrentCookedByteCount
;
1786 ULONG CurrentRawByteCount
;
1791 // We need to maintain our position as we walk through the sectors on the disk.
1792 // We keep separate values for the cooked offset as well as the raw offset.
1793 // These are initialized on sector boundaries and we move through these
1794 // the file sector-by-sector.
1796 // Try to do 32-bit math.
1799 if (((PLARGE_INTEGER
) &CurrentRawOffset
)->HighPart
== 0) {
1802 // Prefix/fast: Note that the following are safe since we only
1803 // take this path for 32bit offsets.
1806 CurrentRawOffset
= (LONGLONG
) ((ULONG
) CurrentRawOffset
/ RAW_SECTOR_SIZE
);
1808 CurrentCookedOffset
= (LONGLONG
) ((ULONG
) CurrentRawOffset
<< SECTOR_SHIFT
);
1810 CurrentRawOffset
= (LONGLONG
) ((ULONG
) CurrentRawOffset
* RAW_SECTOR_SIZE
);
1813 // Otherwise we need to do 64-bit math (sigh).
1818 CurrentRawOffset
/= RAW_SECTOR_SIZE
;
1820 CurrentCookedOffset
= CurrentRawOffset
<< SECTOR_SHIFT
;
1822 CurrentRawOffset
*= RAW_SECTOR_SIZE
;
1826 // Now compute the full number of sectors to be read. Count all of the raw
1827 // sectors that need to be read and convert to cooked bytes.
1830 RawSectorOffset
= (ULONG
) ( StartingOffset
- CurrentRawOffset
) - sizeof( RIFF_HEADER
);
1831 CurrentRawByteCount
= (RawSectorOffset
+ RemainingRawByteCount
+ RAW_SECTOR_SIZE
- 1) / RAW_SECTOR_SIZE
;
1833 RemainingCookedByteCount
= CurrentRawByteCount
<< SECTOR_SHIFT
;
1836 // Initialize the RunCount and ByteCount.
1843 // Loop while there are more bytes to process or there are
1844 // available entries in the IoRun array.
1849 PerformedCopy
= FALSE
;
1853 // Round the scratch buffer up to a sector boundary for alignment.
1856 if (RoundScratchBuffer
) {
1858 if (SectorOffset( ScratchUserBuffer
) != 0) {
1860 CurrentRawByteCount
= SECTOR_SIZE
- SectorOffset( ScratchUserBuffer
);
1862 ScratchUserBuffer
= Add2Ptr( ScratchUserBuffer
,
1863 CurrentRawByteCount
,
1866 ScratchUserBufferOffset
+= CurrentRawByteCount
;
1869 RoundScratchBuffer
= FALSE
;
1873 // Initialize the current position in the IoRuns array. Find the
1874 // eventual destination in the user's buffer for this portion of the transfer.
1877 ThisIoRun
->UserBuffer
= CurrentUserBuffer
;
1880 // Find the allocation information for the current offset in the
1884 CdLookupAllocation( IrpContext
,
1886 CurrentCookedOffset
,
1888 &CurrentCookedByteCount
);
1890 // Maybe we got lucky and this is the same sector as in the
1894 if (DiskOffset
== Fcb
->Vcb
->XADiskOffset
) {
1897 // We will perform safe synchronization. Check again that
1898 // this is the correct sector.
1901 CdLockVcb( IrpContext
, Fcb
->Vcb
);
1903 if ((DiskOffset
== Fcb
->Vcb
->XADiskOffset
) &&
1904 (Fcb
->Vcb
->XASector
!= NULL
)) {
1907 // Copy any bytes we can from the current sector.
1910 CurrentRawByteCount
= RAW_SECTOR_SIZE
- RawSectorOffset
;
1913 // Check whether we don't go to the end of the sector.
1916 if (CurrentRawByteCount
> RemainingRawByteCount
) {
1918 CurrentRawByteCount
= RemainingRawByteCount
;
1921 RtlCopyMemory( CurrentUserBuffer
,
1922 Add2Ptr( Fcb
->Vcb
->XASector
, RawSectorOffset
, PCHAR
),
1923 CurrentRawByteCount
);
1925 CdUnlockVcb( IrpContext
, Fcb
->Vcb
);
1928 // Adjust the run count and pointer in the IoRuns array
1929 // to show that we didn't use a position.
1936 // Remember that we performed a copy operation and update
1937 // the next available position in the scratch buffer.
1940 PerformedCopy
= TRUE
;
1942 ScratchUserBuffer
= Add2Ptr( ScratchUserBuffer
,
1943 CurrentRawByteCount
,
1946 ScratchUserBufferOffset
+= CurrentRawByteCount
;
1948 CurrentCookedByteCount
= SECTOR_SIZE
;
1951 // Set the flag indicating we want to round the scratch buffer
1952 // to a sector boundary.
1955 RoundScratchBuffer
= TRUE
;
1960 // The safe test showed no available buffer. Drop down to common code to
1964 CdUnlockVcb( IrpContext
, Fcb
->Vcb
);
1969 // No work in this pass if we did a copy operation.
1972 if (!PerformedCopy
) {
1975 // Limit ourselves by the number of remaining cooked bytes.
1978 if (CurrentCookedByteCount
> RemainingCookedByteCount
) {
1980 CurrentCookedByteCount
= RemainingCookedByteCount
;
1983 ThisIoRun
->DiskOffset
= DiskOffset
;
1984 ThisIoRun
->TransferBufferOffset
= RawSectorOffset
;
1987 // We will always need to perform copy operations for XA files.
1988 // We allocate an auxillary buffer to read the start of the
1989 // transfer. Then we can use a range of the user's buffer to
1990 // perform the next range of the transfer. Finally we may
1991 // need to allocate a buffer for the tail of the transfer.
1993 // We can use the user's buffer (at the current scratch buffer) if the
1994 // following are true:
1996 // If we are to store the beginning of the raw sector in the user's buffer.
1997 // The current scratch buffer precedes the destination in the user's buffer
1998 // (and hence also lies within it)
1999 // There are enough bytes remaining in the buffer for at least one
2003 if ((RawSectorOffset
== 0) &&
2004 (ScratchUserBufferOffset
<= CurrentUserBufferOffset
) &&
2005 (CurrentUserBufferOffset
- ScratchUserBufferOffset
+ RemainingRawByteCount
>= RAW_SECTOR_SIZE
)) {
2008 // We can use the scratch buffer. We must ensure we don't send down reads
2009 // greater than the device can handle, since the driver is unable to split
2013 if (CurrentCookedByteCount
<= Fcb
->Vcb
->MaximumTransferRawSectors
* SECTOR_SIZE
) {
2015 CurrentRawByteCount
= (SectorAlign( CurrentCookedByteCount
) >> SECTOR_SHIFT
) * RAW_SECTOR_SIZE
;
2019 CurrentCookedByteCount
= Fcb
->Vcb
->MaximumTransferRawSectors
* SECTOR_SIZE
;
2020 CurrentRawByteCount
= Fcb
->Vcb
->MaximumTransferRawSectors
* RAW_SECTOR_SIZE
;
2024 // Now make sure we are within the page transfer limit.
2027 while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer
, RawSectorAlign( CurrentRawByteCount
)) >
2028 Fcb
->Vcb
->MaximumPhysicalPages
) {
2030 CurrentRawByteCount
-= RAW_SECTOR_SIZE
;
2031 CurrentCookedByteCount
-= SECTOR_SIZE
;
2035 // Trim the number of bytes to read if it won't fit into the current buffer. Take
2036 // account of the fact that we must read in whole raw sector multiples.
2039 while ( RawSectorAlign( CurrentRawByteCount
) >
2040 (CurrentUserBufferOffset
- ScratchUserBufferOffset
+ RemainingRawByteCount
) ) {
2042 CurrentRawByteCount
-= RAW_SECTOR_SIZE
;
2043 CurrentCookedByteCount
-= SECTOR_SIZE
;
2047 // Now trim the maximum number of raw bytes to the remaining bytes.
2050 if (CurrentRawByteCount
> RemainingRawByteCount
) {
2052 CurrentRawByteCount
= RemainingRawByteCount
;
2056 // Update the IO run array. We point to the scratch buffer as
2057 // well as the buffer and Mdl in the original Irp.
2060 ThisIoRun
->DiskByteCount
= SectorAlign( CurrentCookedByteCount
);
2063 // Store the number of bytes which we actually care about from this transfer
2066 ThisIoRun
->TransferByteCount
= CurrentRawByteCount
;
2069 // Point to the user's buffer and Mdl for this transfer.
2072 ThisIoRun
->TransferBuffer
= ScratchUserBuffer
;
2073 ThisIoRun
->TransferMdl
= Irp
->MdlAddress
;
2074 ThisIoRun
->TransferVirtualAddress
= Add2Ptr( Irp
->UserBuffer
,
2075 ScratchUserBufferOffset
,
2078 // Update the scratch buffer pointer. Note that since the underlying
2079 // driver stack will always transfer in multiples of raw sectors,
2080 // we must round up here rather than simply advancing by the length of the
2081 // of the data which we actually care about.
2084 ScratchUserBuffer
= Add2Ptr( ScratchUserBuffer
,
2085 RawSectorAlign( CurrentRawByteCount
),
2088 ScratchUserBufferOffset
+= RawSectorAlign( CurrentRawByteCount
);
2091 // Set the flag indicating we want to round the scratch buffer
2092 // to a cooked sector boundary.
2095 RoundScratchBuffer
= TRUE
;
2100 // We need to determine the number of bytes to transfer and the
2101 // offset into this page to begin the transfer.
2103 // We will transfer only one raw sector.
2106 ThisIoRun
->DiskByteCount
= SECTOR_SIZE
;
2108 CurrentCookedByteCount
= SECTOR_SIZE
;
2110 ThisIoRun
->TransferByteCount
= RAW_SECTOR_SIZE
- RawSectorOffset
;
2111 ThisIoRun
->TransferBufferOffset
= RawSectorOffset
;
2113 if (ThisIoRun
->TransferByteCount
> RemainingRawByteCount
) {
2115 ThisIoRun
->TransferByteCount
= RemainingRawByteCount
;
2118 CurrentRawByteCount
= ThisIoRun
->TransferByteCount
;
2121 // We need to allocate an auxillary buffer. We will allocate
2122 // a single page. Then we will build an Mdl to describe the buffer.
2125 ThisIoRun
->TransferBuffer
= FsRtlAllocatePoolWithTag( CdNonPagedPool
, PAGE_SIZE
, TAG_IO_BUFFER
);
2128 // Allocate and build the Mdl to describe this buffer.
2131 ThisIoRun
->TransferMdl
= IoAllocateMdl( ThisIoRun
->TransferBuffer
,
2137 ThisIoRun
->TransferVirtualAddress
= ThisIoRun
->TransferBuffer
;
2139 if (ThisIoRun
->TransferMdl
== NULL
) {
2141 IrpContext
->Irp
->IoStatus
.Information
= 0;
2142 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2145 MmBuildMdlForNonPagedPool( ThisIoRun
->TransferMdl
);
2150 // Update the byte count for our caller.
2153 RemainingRawByteCount
-= CurrentRawByteCount
;
2154 *ThisByteCount
+= CurrentRawByteCount
;
2157 // Break out if no more positions in the IoRuns array or
2158 // we have all of the bytes accounted for.
2161 if ((RemainingRawByteCount
== 0) || (*RunCount
== MAX_PARALLEL_IOS
)) {
2167 // Update our local pointers to allow for the current range of bytes.
2172 CurrentUserBuffer
= Add2Ptr( CurrentUserBuffer
, CurrentRawByteCount
, PVOID
);
2173 CurrentUserBufferOffset
+= CurrentRawByteCount
;
2175 RawSectorOffset
= 0;
2177 CurrentCookedOffset
+= CurrentCookedByteCount
;
2178 RemainingCookedByteCount
-= CurrentCookedByteCount
;
2186 // Local support routine
2191 IN PIRP_CONTEXT IrpContext
,
2194 IN BOOLEAN FinalCleanup
,
2195 IN BOOLEAN SaveXABuffer
2200 Routine Description:
2202 This routine is called to perform any data transferred required for
2203 unaligned Io or to perform the final cleanup of the IoRuns array.
2205 In all cases this is where we will deallocate any buffer and mdl
2206 allocated to perform the unaligned transfer. If this is not the
2207 final cleanup then we also transfer the bytes to the user buffer
2208 and flush the hardware cache.
2210 We walk backwards through the run array because we may be shifting data
2211 in the user's buffer. Typical case is where we allocated a buffer for
2212 the first part of a read and then used the user's buffer for the
2213 next section (but stored it at the beginning of the buffer.
2217 IoRuns - Pointer to the IoRuns array.
2219 RunCount - Number of entries in the IoRuns array filled here.
2221 FinalCleanup - Indicates if we should be deallocating temporary buffers
2222 (TRUE) or transferring bytes for a unaligned transfers and
2223 deallocating the buffers (FALSE). Flush the system cache if
2226 SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
2230 BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
2235 BOOLEAN FlushIoBuffers
= FALSE
;
2237 ULONG RemainingEntries
= RunCount
;
2238 PIO_RUN ThisIoRun
= &IoRuns
[RunCount
- 1];
2244 // Walk through each entry in the IoRun array.
2247 while (RemainingEntries
!= 0) {
2250 // We only need to deal with the case of an unaligned transfer.
2253 if (ThisIoRun
->TransferByteCount
!= 0) {
2256 // If not the final cleanup then transfer the data to the
2257 // user's buffer and remember that we will need to flush
2258 // the user's buffer to memory.
2261 if (!FinalCleanup
) {
2264 // If we are shifting in the user's buffer then use
2268 if (ThisIoRun
->TransferMdl
== IrpContext
->Irp
->MdlAddress
) {
2270 RtlMoveMemory( ThisIoRun
->UserBuffer
,
2271 Add2Ptr( ThisIoRun
->TransferBuffer
,
2272 ThisIoRun
->TransferBufferOffset
,
2274 ThisIoRun
->TransferByteCount
);
2278 RtlCopyMemory( ThisIoRun
->UserBuffer
,
2279 Add2Ptr( ThisIoRun
->TransferBuffer
,
2280 ThisIoRun
->TransferBufferOffset
,
2282 ThisIoRun
->TransferByteCount
);
2285 FlushIoBuffers
= TRUE
;
2289 // Free any Mdl we may have allocated. If the Mdl isn't
2290 // present then we must have failed during the allocation
2294 if (ThisIoRun
->TransferMdl
!= IrpContext
->Irp
->MdlAddress
) {
2296 if (ThisIoRun
->TransferMdl
!= NULL
) {
2298 IoFreeMdl( ThisIoRun
->TransferMdl
);
2302 // Now free any buffer we may have allocated. If the Mdl
2303 // doesn't match the original Mdl then free the buffer.
2306 if (ThisIoRun
->TransferBuffer
!= NULL
) {
2309 // If this is the final buffer for an XA read then store this buffer
2310 // into the Vcb so that we will have it when reading any remaining
2311 // portion of this buffer.
2316 Vcb
= IrpContext
->Vcb
;
2318 CdLockVcb( IrpContext
, Vcb
);
2320 if (Vcb
->XASector
!= NULL
) {
2322 CdFreePool( &Vcb
->XASector
);
2325 Vcb
->XASector
= ThisIoRun
->TransferBuffer
;
2326 Vcb
->XADiskOffset
= ThisIoRun
->DiskOffset
;
2328 SaveXABuffer
= FALSE
;
2330 CdUnlockVcb( IrpContext
, Vcb
);
2333 // Otherwise just free the buffer.
2338 CdFreePool( &ThisIoRun
->TransferBuffer
);
2345 // Now handle the case where we failed in the process
2346 // of allocating associated Irps and Mdls.
2349 if (ThisIoRun
->SavedIrp
!= NULL
) {
2351 if (ThisIoRun
->SavedIrp
->MdlAddress
!= NULL
) {
2353 IoFreeMdl( ThisIoRun
->SavedIrp
->MdlAddress
);
2356 IoFreeIrp( ThisIoRun
->SavedIrp
);
2360 // Move to the previous IoRun entry.
2364 RemainingEntries
-= 1;
2368 // If we copied any data then flush the Io buffers.
2371 return FlushIoBuffers
;
2376 // Local support routine
2381 IN PIRP_CONTEXT IrpContext
,
2388 Routine Description:
2390 This routine first does the initial setup required of a Master IRP that is
2391 going to be completed using associated IRPs. This routine should not
2392 be used if only one async request is needed, instead the single read
2393 async routines should be called.
2395 A context parameter is initialized, to serve as a communications area
2396 between here and the common completion routine.
2398 Next this routine reads or writes one or more contiguous sectors from
2399 a device asynchronously, and is used if there are multiple reads for a
2400 master IRP. A completion routine is used to synchronize with the
2401 completion of all of the I/O requests started by calls to this routine.
2403 Also, prior to calling this routine the caller must initialize the
2404 IoStatus field in the Context, with the correct success status and byte
2405 count which are expected if all of the parallel transfers complete
2406 successfully. After return this status will be unchanged if all requests
2407 were, in fact, successful. However, if one or more errors occur, the
2408 IoStatus will be modified to reflect the error status and byte count
2409 from the first run (by Vbo) which encountered an error. I/O status
2410 from all subsequent runs will not be indicated.
2414 RunCount - Supplies the number of multiple async requests
2415 that will be issued against the master irp.
2417 IoRuns - Supplies an array containing the Offset and ByteCount for the
2427 PIO_COMPLETION_ROUTINE CompletionRoutine
;
2428 PIO_STACK_LOCATION IrpSp
;
2432 ULONG UnwindRunCount
;
2437 // Set up things according to whether this is truely async.
2440 CompletionRoutine
= CdMultiSyncCompletionRoutine
;
2442 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
2444 CompletionRoutine
= CdMultiAsyncCompletionRoutine
;
2448 // Initialize some local variables.
2451 MasterIrp
= IrpContext
->Irp
;
2454 // Iterate through the runs, doing everything that can fail.
2455 // We let the cleanup in CdFinishBuffers clean up on error.
2458 for (UnwindRunCount
= 0;
2459 UnwindRunCount
< RunCount
;
2460 UnwindRunCount
+= 1) {
2463 // Create an associated IRP, making sure there is one stack entry for
2467 IoRuns
[UnwindRunCount
].SavedIrp
=
2468 Irp
= IoMakeAssociatedIrp( MasterIrp
, (CCHAR
)(IrpContext
->Vcb
->TargetDeviceObject
->StackSize
+ 1) );
2472 IrpContext
->Irp
->IoStatus
.Information
= 0;
2473 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2477 // Allocate and build a partial Mdl for the request.
2480 Mdl
= IoAllocateMdl( IoRuns
[UnwindRunCount
].TransferVirtualAddress
,
2481 IoRuns
[UnwindRunCount
].DiskByteCount
,
2488 IrpContext
->Irp
->IoStatus
.Information
= 0;
2489 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2492 IoBuildPartialMdl( IoRuns
[UnwindRunCount
].TransferMdl
,
2494 IoRuns
[UnwindRunCount
].TransferVirtualAddress
,
2495 IoRuns
[UnwindRunCount
].DiskByteCount
);
2498 // Get the first IRP stack location in the associated Irp
2501 IoSetNextIrpStackLocation( Irp
);
2502 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2505 // Setup the Stack location to describe our read.
2508 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2509 IrpSp
->Parameters
.Read
.Length
= IoRuns
[UnwindRunCount
].DiskByteCount
;
2510 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= IoRuns
[UnwindRunCount
].DiskOffset
;
2513 // Set up the completion routine address in our stack frame.
2516 IoSetCompletionRoutine( Irp
,
2518 IrpContext
->IoContext
,
2524 // Setup the next IRP stack location in the associated Irp for the disk
2525 // driver beneath us.
2528 IrpSp
= IoGetNextIrpStackLocation( Irp
);
2531 // Setup the Stack location to do a read from the disk driver.
2534 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2535 IrpSp
->Parameters
.Read
.Length
= IoRuns
[UnwindRunCount
].DiskByteCount
;
2536 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= IoRuns
[UnwindRunCount
].DiskOffset
;
2540 // We only need to set the associated IRP count in the master irp to
2541 // make it a master IRP. But we set the count to one more than our
2542 // caller requested, because we do not want the I/O system to complete
2543 // the I/O. We also set our own count.
2546 IrpContext
->IoContext
->IrpCount
= RunCount
;
2547 IrpContext
->IoContext
->MasterIrp
= MasterIrp
;
2550 // We set the count in the master Irp to 1 since typically we
2551 // will clean up the associated irps ourselves. Setting this to one
2552 // means completing the last associated Irp with SUCCESS (in the async
2553 // case) will complete the master irp.
2556 MasterIrp
->AssociatedIrp
.IrpCount
= 1;
2559 // Now that all the dangerous work is done, issue the Io requests
2562 for (UnwindRunCount
= 0;
2563 UnwindRunCount
< RunCount
;
2566 Irp
= IoRuns
[UnwindRunCount
].SavedIrp
;
2567 IoRuns
[UnwindRunCount
].SavedIrp
= NULL
;
2570 // If IoCallDriver returns an error, it has completed the Irp
2571 // and the error will be caught by our completion routines
2572 // and dealt with as a normal IO error.
2575 (VOID
) IoCallDriver( IrpContext
->Vcb
->TargetDeviceObject
, Irp
);
2583 // Local support routine
2588 IN PIRP_CONTEXT IrpContext
,
2591 IN PRAW_READ_INFO RawReads
,
2592 IN TRACK_MODE_TYPE TrackMode
2597 Routine Description:
2599 This routine first does the initial setup required of a Master IRP that is
2600 going to be completed using associated IRPs. This routine is used to generate
2601 the associated Irps used to read raw sectors from the disk.
2603 A context parameter is initialized, to serve as a communications area
2604 between here and the common completion routine.
2606 Next this routine reads or writes one or more contiguous sectors from
2607 a device asynchronously, and is used if there are multiple reads for a
2608 master IRP. A completion routine is used to synchronize with the
2609 completion of all of the I/O requests started by calls to this routine.
2611 Also, prior to calling this routine the caller must initialize the
2612 IoStatus field in the Context, with the correct success status and byte
2613 count which are expected if all of the parallel transfers complete
2614 successfully. After return this status will be unchanged if all requests
2615 were, in fact, successful. However, if one or more errors occur, the
2616 IoStatus will be modified to reflect the error status and byte count
2617 from the first run (by Vbo) which encountered an error. I/O status
2618 from all subsequent runs will not be indicated.
2622 RunCount - Supplies the number of multiple async requests
2623 that will be issued against the master irp.
2625 IoRuns - Supplies an array containing the Offset and ByteCount for the
2628 RawReads - Supplies an array of structures to store in the Irps passed to the
2629 device driver to perform the low-level Io.
2631 TrackMode - Supplies the recording mode of sectors in these IoRuns
2640 PIO_STACK_LOCATION IrpSp
;
2644 ULONG UnwindRunCount
;
2647 PIO_RUN ThisIoRun
= IoRuns
;
2648 PRAW_READ_INFO ThisRawRead
= RawReads
;
2653 // Initialize some local variables.
2656 MasterIrp
= IrpContext
->Irp
;
2659 // Iterate through the runs, doing everything that can fail.
2660 // We let the cleanup in CdFinishBuffers clean up on error.
2663 for (UnwindRunCount
= 0;
2664 UnwindRunCount
< RunCount
;
2665 UnwindRunCount
+= 1, ThisIoRun
+= 1, ThisRawRead
+= 1) {
2668 // Create an associated IRP, making sure there is one stack entry for
2672 ThisIoRun
->SavedIrp
=
2673 Irp
= IoMakeAssociatedIrp( MasterIrp
, (CCHAR
)(IrpContext
->Vcb
->TargetDeviceObject
->StackSize
+ 1) );
2677 IrpContext
->Irp
->IoStatus
.Information
= 0;
2678 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2682 // Should have been passed a byte count of at least one sector, and
2683 // must be a multiple of sector size
2686 ASSERT( ThisIoRun
->DiskByteCount
&& !SectorOffset(ThisIoRun
->DiskByteCount
));
2688 RawByteCount
= SectorsFromBytes( ThisIoRun
->DiskByteCount
) * RAW_SECTOR_SIZE
;
2691 // Allocate and build a partial Mdl for the request.
2694 Mdl
= IoAllocateMdl( ThisIoRun
->TransferVirtualAddress
,
2702 IrpContext
->Irp
->IoStatus
.Information
= 0;
2703 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
2706 IoBuildPartialMdl( ThisIoRun
->TransferMdl
,
2708 ThisIoRun
->TransferVirtualAddress
,
2711 // Get the first IRP stack location in the associated Irp
2714 IoSetNextIrpStackLocation( Irp
);
2715 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
2718 // Setup the Stack location to describe our read (using cooked values)
2719 // These values won't be used for the raw read in any case.
2722 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2723 IrpSp
->Parameters
.Read
.Length
= ThisIoRun
->DiskByteCount
;
2724 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= ThisIoRun
->DiskOffset
;
2727 // Set up the completion routine address in our stack frame.
2730 IoSetCompletionRoutine( Irp
,
2731 CdMultiSyncCompletionRoutine
,
2732 IrpContext
->IoContext
,
2738 // Setup the next IRP stack location in the associated Irp for the disk
2739 // driver beneath us.
2742 IrpSp
= IoGetNextIrpStackLocation( Irp
);
2745 // Setup the stack location to do a read of raw sectors at this location.
2746 // Note that the storage stack always reads multiples of whole XA sectors.
2749 ThisRawRead
->DiskOffset
.QuadPart
= ThisIoRun
->DiskOffset
;
2750 ThisRawRead
->SectorCount
= ThisIoRun
->DiskByteCount
>> SECTOR_SHIFT
;
2751 ThisRawRead
->TrackMode
= TrackMode
;
2753 IrpSp
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
2755 IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
= ThisRawRead
->SectorCount
* RAW_SECTOR_SIZE
;
2756 Irp
->UserBuffer
= ThisIoRun
->TransferVirtualAddress
;
2758 IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
= sizeof( RAW_READ_INFO
);
2759 IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
= ThisRawRead
;
2761 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_CDROM_RAW_READ
;
2765 // We only need to set the associated IRP count in the master irp to
2766 // make it a master IRP. But we set the count to one more than our
2767 // caller requested, because we do not want the I/O system to complete
2768 // the I/O. We also set our own count.
2771 IrpContext
->IoContext
->IrpCount
= RunCount
;
2772 IrpContext
->IoContext
->MasterIrp
= MasterIrp
;
2775 // We set the count in the master Irp to 1 since typically we
2776 // will clean up the associated irps ourselves. Setting this to one
2777 // means completing the last associated Irp with SUCCESS (in the async
2778 // case) will complete the master irp.
2781 MasterIrp
->AssociatedIrp
.IrpCount
= 1;
2784 // Now that all the dangerous work is done, issue the Io requests
2787 for (UnwindRunCount
= 0;
2788 UnwindRunCount
< RunCount
;
2791 Irp
= IoRuns
[UnwindRunCount
].SavedIrp
;
2792 IoRuns
[UnwindRunCount
].SavedIrp
= NULL
;
2796 // If IoCallDriver returns an error, it has completed the Irp
2797 // and the error will be caught by our completion routines
2798 // and dealt with as a normal IO error.
2801 (VOID
) IoCallDriver( IrpContext
->Vcb
->TargetDeviceObject
, Irp
);
2809 // Local support routine
2814 IN PIRP_CONTEXT IrpContext
,
2815 IN LONGLONG ByteOffset
,
2821 Routine Description:
2823 This routine reads one or more contiguous sectors from a device
2824 asynchronously, and is used if there is only one read necessary to
2825 complete the IRP. It implements the read by simply filling
2826 in the next stack frame in the Irp, and passing it on. The transfer
2827 occurs to the single buffer originally specified in the user request.
2831 ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
2833 ByteCount - Supplies the number of bytes to read from the device
2842 PIO_STACK_LOCATION IrpSp
;
2843 PIO_COMPLETION_ROUTINE CompletionRoutine
;
2848 // Set up things according to whether this is truely async.
2851 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
2853 CompletionRoutine
= CdSingleSyncCompletionRoutine
;
2857 CompletionRoutine
= CdSingleAsyncCompletionRoutine
;
2861 // Set up the completion routine address in our stack frame.
2864 IoSetCompletionRoutine( IrpContext
->Irp
,
2866 IrpContext
->IoContext
,
2872 // Setup the next IRP stack location in the associated Irp for the disk
2873 // driver beneath us.
2876 IrpSp
= IoGetNextIrpStackLocation( IrpContext
->Irp
);
2879 // Setup the Stack location to do a read from the disk driver.
2882 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2883 IrpSp
->Parameters
.Read
.Length
= ByteCount
;
2884 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= ByteOffset
;
2887 // Issue the Io request
2891 // If IoCallDriver returns an error, it has completed the Irp
2892 // and the error will be caught by our completion routines
2893 // and dealt with as a normal IO error.
2896 (VOID
)IoCallDriver( IrpContext
->Vcb
->TargetDeviceObject
, IrpContext
->Irp
);
2899 // And return to our caller
2907 // Local support routine
2912 IN PIRP_CONTEXT IrpContext
2917 Routine Description:
2919 This routine waits for one or more previously started I/O requests
2920 from the above routines, by simply waiting on the event.
2933 KeWaitForSingleObject( &IrpContext
->IoContext
->SyncEvent
,
2939 KeClearEvent( &IrpContext
->IoContext
->SyncEvent
);
2946 // Local support routine
2950 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
2951 CdMultiSyncCompletionRoutine (
2952 IN PDEVICE_OBJECT DeviceObject
,
2959 Routine Description:
2961 This is the completion routine for all synchronous reads
2962 started via CdMultipleAsynch.
2964 The completion routine has has the following responsibilities:
2966 If the individual request was completed with an error, then
2967 this completion routine must see if this is the first error
2968 and remember the error status in the Context.
2970 If the IrpCount goes to 1, then it sets the event in the Context
2971 parameter to signal the caller that all of the asynch requests
2976 DeviceObject - Pointer to the file system device object.
2978 Irp - Pointer to the associated Irp which is being completed. (This
2979 Irp will no longer be accessible after this routine returns.)
2981 Context - The context parameter which was specified for all of
2982 the multiple asynch I/O requests for this MasterIrp.
2986 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
2987 immediately complete the Master Irp without being in a race condition
2988 with the IoCompleteRequest thread trying to decrement the IrpCount in
2994 PCD_IO_CONTEXT IoContext
= Context
;
2996 AssertVerifyDeviceIrp( Irp
);
2999 // If we got an error (or verify required), remember it in the Irp
3002 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3004 InterlockedExchange( &IoContext
->Status
, Irp
->IoStatus
.Status
);
3005 IoContext
->MasterIrp
->IoStatus
.Information
= 0;
3009 // We must do this here since IoCompleteRequest won't get a chance
3010 // on this associated Irp.
3013 IoFreeMdl( Irp
->MdlAddress
);
3016 if (InterlockedDecrement( &IoContext
->IrpCount
) == 0) {
3019 // Update the Master Irp with any error status from the associated Irps.
3022 IoContext
->MasterIrp
->IoStatus
.Status
= IoContext
->Status
;
3023 KeSetEvent( &IoContext
->SyncEvent
, 0, FALSE
);
3026 UNREFERENCED_PARAMETER( DeviceObject
);
3028 return STATUS_MORE_PROCESSING_REQUIRED
;
3033 // Local support routine
3037 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3038 CdMultiAsyncCompletionRoutine (
3039 IN PDEVICE_OBJECT DeviceObject
,
3046 Routine Description:
3048 This is the completion routine for all asynchronous reads
3049 started via CdMultipleAsynch.
3051 The completion routine has has the following responsibilities:
3053 If the individual request was completed with an error, then
3054 this completion routine must see if this is the first error
3055 and remember the error status in the Context.
3059 DeviceObject - Pointer to the file system device object.
3061 Irp - Pointer to the associated Irp which is being completed. (This
3062 Irp will no longer be accessible after this routine returns.)
3064 Context - The context parameter which was specified for all of
3065 the multiple asynch I/O requests for this MasterIrp.
3069 Currently always returns STATUS_SUCCESS.
3074 PCD_IO_CONTEXT IoContext
= Context
;
3075 /* ReactOS Change: GCC Unused Variable */
3076 //PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
3078 AssertVerifyDeviceIrp( Irp
);
3081 // If we got an error (or verify required), remember it in the Irp
3084 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3086 InterlockedExchange( &IoContext
->Status
, Irp
->IoStatus
.Status
);
3090 // Decrement IrpCount and see if it goes to zero.
3093 if (InterlockedDecrement( &IoContext
->IrpCount
) == 0) {
3096 // Mark the master Irp pending
3099 IoMarkIrpPending( IoContext
->MasterIrp
);
3102 // Update the Master Irp with any error status from the associated Irps.
3105 IoContext
->MasterIrp
->IoStatus
.Status
= IoContext
->Status
;
3108 // Update the information field with the correct value.
3111 IoContext
->MasterIrp
->IoStatus
.Information
= 0;
3113 if (NT_SUCCESS( IoContext
->MasterIrp
->IoStatus
.Status
)) {
3115 IoContext
->MasterIrp
->IoStatus
.Information
= IoContext
->RequestedByteCount
;
3119 // Now release the resource
3122 ExReleaseResourceForThreadLite( IoContext
->Resource
,
3123 IoContext
->ResourceThreadId
);
3126 // and finally, free the context record.
3129 CdFreeIoContext( IoContext
);
3132 // Return success in this case.
3135 return STATUS_SUCCESS
;
3140 // We need to cleanup the associated Irp and its Mdl.
3143 IoFreeMdl( Irp
->MdlAddress
);
3146 return STATUS_MORE_PROCESSING_REQUIRED
;
3149 UNREFERENCED_PARAMETER( DeviceObject
);
3154 // Local support routine
3158 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3159 CdSingleSyncCompletionRoutine (
3160 IN PDEVICE_OBJECT DeviceObject
,
3167 Routine Description:
3169 This is the completion routine for all reads started via CdSingleAsynch.
3171 The completion routine has has the following responsibilities:
3173 It sets the event in the Context parameter to signal the caller
3174 that all of the asynch requests are done.
3178 DeviceObject - Pointer to the file system device object.
3180 Irp - Pointer to the Irp for this request. (This Irp will no longer
3181 be accessible after this routine returns.)
3183 Context - The context parameter which was specified in the call to
3188 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3189 immediately complete the Master Irp without being in a race condition
3190 with the IoCompleteRequest thread trying to decrement the IrpCount in
3196 AssertVerifyDeviceIrp( Irp
);
3199 // Store the correct information field into the Irp.
3202 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3204 Irp
->IoStatus
.Information
= 0;
3207 KeSetEvent( &((PCD_IO_CONTEXT
)Context
)->SyncEvent
, 0, FALSE
);
3209 return STATUS_MORE_PROCESSING_REQUIRED
;
3214 // Local support routine
3218 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3219 CdSingleAsyncCompletionRoutine (
3220 IN PDEVICE_OBJECT DeviceObject
,
3227 Routine Description:
3229 This is the completion routine for all asynchronous reads
3230 started via CdSingleAsynch.
3234 DeviceObject - Pointer to the file system device object.
3236 Irp - Pointer to the Irp for this request. (This Irp will no longer
3237 be accessible after this routine returns.)
3239 Context - The context parameter which was specified in the call to
3244 Currently always returns STATUS_SUCCESS.
3249 AssertVerifyDeviceIrp( Irp
);
3252 // Update the information field with the correct value for bytes read.
3255 Irp
->IoStatus
.Information
= 0;
3257 if (NT_SUCCESS( Irp
->IoStatus
.Status
)) {
3259 Irp
->IoStatus
.Information
= ((PCD_IO_CONTEXT
) Context
)->RequestedByteCount
;
3263 // Mark the Irp pending
3266 IoMarkIrpPending( Irp
);
3269 // Now release the resource
3272 ExReleaseResourceForThreadLite( ((PCD_IO_CONTEXT
) Context
)->Resource
,
3273 ((PCD_IO_CONTEXT
) Context
)->ResourceThreadId
);
3276 // and finally, free the context record.
3279 CdFreeIoContext( Context
); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
3280 return STATUS_SUCCESS
;
3282 UNREFERENCED_PARAMETER( DeviceObject
);
3287 // Local support routine
3291 CdReadAudioSystemFile (
3292 IN PIRP_CONTEXT IrpContext
,
3294 IN LONGLONG StartingOffset
,
3296 IN PVOID SystemBuffer
3301 Routine Description:
3303 This routine is called to read the pseudo root directory and path
3304 table for a music disk. We build the individual elements on the
3305 stack and copy into the cache buffer.
3309 Fcb - Fcb representing the file to read.
3311 StartingOffset - Logical offset in the file to read from.
3313 ByteCount - Number of bytes to read.
3315 SystemBuffer - Pointer to buffer to fill in. This will always be page
3325 PRAW_PATH_ISO RawPath
;
3326 PRAW_DIRENT RawDirent
;
3333 PTRACK_DATA ThisTrack
;
3335 LONGLONG CurrentOffset
;
3337 PVOID CurrentSector
;
3339 PSYSTEM_USE_XA SystemUse
;
3343 UCHAR LocalBuffer
[FIELD_OFFSET( RAW_DIRENT
, FileId
) + 12];
3348 // If this is the path table then we just need a single entry.
3351 if (SafeNodeType( Fcb
) == CDFS_NTC_FCB_PATH_TABLE
) {
3354 // Sanity check that the offset is zero.
3357 ASSERT( StartingOffset
== 0 );
3360 // Store a pseudo path entry in our local buffer.
3363 RawPath
= (PRAW_PATH_ISO
) LocalBuffer
;
3365 RtlZeroMemory( RawPath
, sizeof( LocalBuffer
));
3367 RawPath
->DirIdLen
= 1;
3368 RawPath
->ParentNum
= 1;
3369 RawPath
->DirId
[0] = '\0';
3372 // Now copy to the user's buffer.
3375 BytesToCopy
= FIELD_OFFSET( RAW_PATH_ISO
, DirId
) + 2;
3377 if (BytesToCopy
> ByteCount
) {
3379 BytesToCopy
= ByteCount
;
3382 RtlCopyMemory( SystemBuffer
,
3387 // We need to deal with the multiple sector case for the root directory.
3393 // Initialize the first track to return to our caller.
3399 // If the offset is zero then store the entries for the self and parent
3403 if (StartingOffset
== 0) {
3405 RawDirent
= SystemBuffer
;
3408 // Clear all of the fields initially.
3411 RtlZeroMemory( RawDirent
, FIELD_OFFSET( RAW_DIRENT
, FileId
));
3414 // Now fill in the interesting fields.
3417 RawDirent
->DirLen
= FIELD_OFFSET( RAW_DIRENT
, FileId
) + 1;
3418 RawDirent
->FileIdLen
= 1;
3419 RawDirent
->FileId
[0] = '\0';
3420 SetFlag( RawDirent
->FlagsISO
, CD_ATTRIBUTE_DIRECTORY
);
3423 // Set the time stamp to be Jan 1, 1995
3426 RawDirent
->RecordTime
[0] = 95;
3427 RawDirent
->RecordTime
[1] = 1;
3428 RawDirent
->RecordTime
[2] = 1;
3430 SectorOffset
= RawDirent
->DirLen
;
3432 RawDirent
= Add2Ptr( RawDirent
, SectorOffset
, PRAW_DIRENT
);
3435 // Clear all of the fields initially.
3438 RtlZeroMemory( RawDirent
, FIELD_OFFSET( RAW_DIRENT
, FileId
));
3441 // Now fill in the interesting fields.
3444 RawDirent
->DirLen
= FIELD_OFFSET( RAW_DIRENT
, FileId
) + 1;
3445 RawDirent
->FileIdLen
= 1;
3446 RawDirent
->FileId
[0] = '\1';
3447 SetFlag( RawDirent
->FlagsISO
, CD_ATTRIBUTE_DIRECTORY
);
3450 // Set the time stamp to be Jan 1, 1995
3453 RawDirent
->RecordTime
[0] = 95;
3454 RawDirent
->RecordTime
[1] = 1;
3455 RawDirent
->RecordTime
[2] = 1;
3457 SectorOffset
+= RawDirent
->DirLen
;
3461 // Otherwise compute the starting track to write to the buffer.
3467 // Count the tracks in each preceding sector.
3474 CurrentTrack
+= CdAudioDirentsPerSector
;
3475 CurrentOffset
+= SECTOR_SIZE
;
3477 } while (CurrentOffset
< StartingOffset
);
3480 // Bias the track count to reflect the two default entries.
3490 // We now know the first track to return as well as where we are in
3491 // the current sector. We will walk through sector by sector adding
3492 // the entries for the separate tracks in the TOC. We will zero
3493 // any sectors or partial sectors without data.
3496 CurrentSector
= SystemBuffer
;
3497 BytesToCopy
= SECTOR_SIZE
;
3500 // Loop for each sector.
3506 // Add entries until we reach our threshold for each sector.
3512 // If we are beyond the entries in the TOC then exit.
3515 if (CurrentTrack
>= IrpContext
->Vcb
->TrackCount
) {
3520 ThisTrack
= &IrpContext
->Vcb
->CdromToc
->TrackData
[CurrentTrack
];
3523 // Point to the current position in the buffer.
3526 RawDirent
= Add2Ptr( CurrentSector
, SectorOffset
, PRAW_DIRENT
);
3529 // Clear all of the fields initially.
3532 RtlZeroMemory( RawDirent
, CdAudioDirentSize
);
3535 // Now fill in the interesting fields.
3538 RawDirent
->DirLen
= (UCHAR
) CdAudioDirentSize
;
3539 RawDirent
->FileIdLen
= CdAudioFileNameLength
;
3541 RtlCopyMemory( RawDirent
->FileId
,
3543 CdAudioFileNameLength
);
3546 // Set the time stamp to be Jan 1, 1995
3549 RawDirent
->RecordTime
[0] = 95;
3550 RawDirent
->RecordTime
[1] = 1;
3551 RawDirent
->RecordTime
[2] = 1;
3554 // Now bias by the values in the TOC.
3557 RawDirent
->RecordTime
[4] = ThisTrack
->Address
[1] % 60;
3558 RawDirent
->RecordTime
[5] = ThisTrack
->Address
[2] % 60;
3561 // Put the track number into the file name.
3564 TrackTens
= TrackOnes
= ThisTrack
->TrackNumber
;
3566 TrackOnes
= (TrackOnes
% 10) + '0';
3569 TrackTens
= (TrackTens
% 10) + '0';
3571 RawDirent
->FileId
[AUDIO_NAME_TENS_OFFSET
] = TrackTens
;
3572 RawDirent
->FileId
[AUDIO_NAME_ONES_OFFSET
] = TrackOnes
;
3574 SystemUse
= Add2Ptr( RawDirent
, CdAudioSystemUseOffset
, PSYSTEM_USE_XA
);
3576 SystemUse
->Attributes
= SYSTEM_USE_XA_DA
;
3577 SystemUse
->Signature
= SYSTEM_XA_SIGNATURE
;
3580 // Store the track number as the file number.
3583 SystemUse
->FileNumber
= (UCHAR
) CurrentTrack
;
3586 SectorOffset
+= CdAudioDirentSize
;
3589 } while (EntryCount
< CdAudioDirentsPerSector
);
3592 // Zero the remaining portion of this buffer.
3595 RtlZeroMemory( Add2Ptr( CurrentSector
, SectorOffset
, PVOID
),
3596 SECTOR_SIZE
- SectorOffset
);
3599 // Prepare for the next sector.
3603 BytesToCopy
+= SECTOR_SIZE
;
3605 CurrentSector
= Add2Ptr( CurrentSector
, SECTOR_SIZE
, PVOID
);
3607 } while (BytesToCopy
<= ByteCount
);