--*/
-#include "CdProcs.h"
+#include "cdprocs.h"
//
// The Bug check file id for this module
// Local support routines
//
+_Requires_lock_held_(_Global_critical_region_)
BOOLEAN
CdPrepareBuffers (
- IN PIRP_CONTEXT IrpContext,
- IN PIRP Irp,
- IN PFCB Fcb,
- IN PVOID UserBuffer,
- IN ULONG UserBufferOffset,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN PIO_RUN IoRuns,
- IN PULONG RunCount,
- IN PULONG ThisByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIRP Irp,
+ _In_ PFCB Fcb,
+ _In_reads_bytes_(ByteCount) PVOID UserBuffer,
+ _In_ ULONG UserBufferOffset,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount,
+ _Out_ PIO_RUN IoRuns,
+ _Out_ PULONG RunCount,
+ _Out_ PULONG ThisByteCount
);
+_Requires_lock_held_(_Global_critical_region_)
VOID
CdPrepareXABuffers (
- IN PIRP_CONTEXT IrpContext,
- IN PIRP Irp,
- IN PFCB Fcb,
- IN PVOID UserBuffer,
- IN ULONG UserBufferOffset,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN PIO_RUN IoRuns,
- IN PULONG RunCount,
- IN PULONG ThisByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIRP Irp,
+ _In_ PFCB Fcb,
+ _In_reads_bytes_(ByteCount) PVOID UserBuffer,
+ _In_ ULONG UserBufferOffset,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount,
+ _Out_ PIO_RUN IoRuns,
+ _Out_ PULONG RunCount,
+ _Out_ PULONG ThisByteCount
);
BOOLEAN
CdFinishBuffers (
- IN PIRP_CONTEXT IrpContext,
- IN PIO_RUN IoRuns,
- IN ULONG RunCount,
- IN BOOLEAN FinalCleanup,
- IN BOOLEAN SaveXABuffer
+ _In_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIO_RUN IoRuns,
+ _In_ ULONG RunCount,
+ _In_ BOOLEAN FinalCleanup,
+ _In_ BOOLEAN SaveXABuffer
);
+_Requires_lock_held_(_Global_critical_region_)
VOID
CdMultipleAsync (
- IN PIRP_CONTEXT IrpContext,
- IN ULONG RunCount,
- IN PIO_RUN IoRuns
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ ULONG RunCount,
+ _Inout_ PIO_RUN IoRuns
);
VOID
CdMultipleXAAsync (
- IN PIRP_CONTEXT IrpContext,
- IN ULONG RunCount,
- IN PIO_RUN IoRuns,
- IN PRAW_READ_INFO RawReads,
- IN TRACK_MODE_TYPE TrackMode
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ ULONG RunCount,
+ _Inout_ PIO_RUN IoRuns,
+ _In_ PRAW_READ_INFO RawReads,
+ _In_ TRACK_MODE_TYPE TrackMode
);
+_Requires_lock_held_(_Global_critical_region_)
VOID
CdSingleAsync (
- IN PIRP_CONTEXT IrpContext,
- IN LONGLONG ByteOffset,
- IN ULONG ByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIO_RUN Run,
+ _In_ PFCB Fcb
);
VOID
CdWaitSync (
- IN PIRP_CONTEXT IrpContext
+ _In_ PIRP_CONTEXT IrpContext
);
-NTSTATUS
-NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
-CdMultiSyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- );
+// Tell prefast this is a completion routine.
+IO_COMPLETION_ROUTINE CdMultiSyncCompletionRoutine;
-NTSTATUS
-NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
-CdMultiAsyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- );
+// Tell prefast this is a completion routine
+IO_COMPLETION_ROUTINE CdMultiAsyncCompletionRoutine;
-NTSTATUS
-NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
-CdSingleSyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- );
+// Tell prefast this is a completion routine
+IO_COMPLETION_ROUTINE CdSingleSyncCompletionRoutine;
-NTSTATUS
-NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
-CdSingleAsyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
- );
+// Tell prefast this is a completion routine
+IO_COMPLETION_ROUTINE CdSingleAsyncCompletionRoutine;
+_When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT))))
+_When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE)))
VOID
CdReadAudioSystemFile (
- IN PIRP_CONTEXT IrpContext,
- IN PFCB Fcb,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN PVOID SystemBuffer
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ LONGLONG StartingOffset,
+ _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount,
+ _Out_writes_bytes_(ByteCount) PVOID SystemBuffer
+ );
+
+_Requires_lock_held_(_Global_critical_region_)
+BOOLEAN
+CdReadDirDataThroughCache (
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIO_RUN Run
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CdMultipleXAAsync)
#pragma alloc_text(PAGE, CdNonCachedRead)
#pragma alloc_text(PAGE, CdNonCachedXARead)
+#pragma alloc_text(PAGE, CdVolumeDasdWrite)
#pragma alloc_text(PAGE, CdFinishBuffers)
#pragma alloc_text(PAGE, CdPerformDevIoCtrl)
+#pragma alloc_text(PAGE, CdPerformDevIoCtrlEx)
#pragma alloc_text(PAGE, CdPrepareBuffers)
+#pragma alloc_text(PAGE, CdPrepareXABuffers)
#pragma alloc_text(PAGE, CdReadAudioSystemFile)
#pragma alloc_text(PAGE, CdReadSectors)
#pragma alloc_text(PAGE, CdSingleAsync)
#pragma alloc_text(PAGE, CdWaitSync)
+#pragma alloc_text(PAGE, CdReadDirDataThroughCache)
+#pragma alloc_text(PAGE, CdFreeDirCache)
+#pragma alloc_text(PAGE, CdLbnToMmSsFf)
+#pragma alloc_text(PAGE, CdHijackIrpAndFlushDevice)
#endif
-\f
+
+VOID
+CdLbnToMmSsFf (
+ _In_ ULONG Blocks,
+ _Out_writes_(3) PUCHAR Msf
+ )
+
+/*++
+
+Routine Description:
+
+ Convert Lbn to MSF format.
+
+Arguments:
+
+ Msf - on output, set to 0xMmSsFf representation of blocks.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ Blocks += 150; // Lbn 0 == 00:02:00, 1sec == 75 frames.
+
+ Msf[0] = (UCHAR)(Blocks % 75); // Frames
+ Blocks /= 75; // -> Seconds
+ Msf[1] = (UCHAR)(Blocks % 60); // Seconds
+ Blocks /= 60; // -> Minutes
+ Msf[2] = (UCHAR)Blocks; // Minutes
+}
+
+
__inline
TRACK_MODE_TYPE
CdFileTrackMode (
- IN PFCB Fcb
+ _In_ PFCB Fcb
)
/*++
--*/
{
- ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE |
+ NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE |
FCB_STATE_MODE2_FILE |
FCB_STATE_DA_FILE ));
}
\f
+_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdNonCachedRead (
- IN PIRP_CONTEXT IrpContext,
- IN PFCB Fcb,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount
)
/*++
if (IrpContext->Irp->MdlAddress == NULL) {
- CdCreateUserMdl( IrpContext, ByteCount, TRUE );
+ CdCreateUserMdl( IrpContext, ByteCount, TRUE, IoWriteAccess );
}
CdMapUserBuffer( IrpContext, &UserBuffer);
return STATUS_SUCCESS;
}
+ //
+ // If we're going to use the sector cache for this request, then
+ // mark the request waitable.
+ //
+
+ if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
+ (NULL != Fcb->Vcb->SectorCacheBuffer) &&
+ (VcbMounted == IrpContext->Vcb->VcbCondition)) {
+
+ if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
+
+ KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
+ NotificationEvent,
+ FALSE );
+
+ SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+ }
+ }
+
//
// Use a try-finally to perform the final cleanup.
//
- try {
+ _SEH2_TRY {
//
// Loop while there are more bytes to transfer.
if ((RunCount == 1) && !Unaligned && FirstPass) {
- CdSingleAsync( IrpContext,
- IoRuns[0].DiskOffset,
- IoRuns[0].DiskByteCount );
+ CdSingleAsync( IrpContext,&IoRuns[0], Fcb );
//
// No cleanup needed for the IoRuns array here.
// Otherwise we will perform multiple Io to read in the data.
//
- CdMultipleAsync( IrpContext, RunCount, IoRuns );
+ CdMultipleAsync( IrpContext, Fcb, RunCount, IoRuns );
//
// If this is a synchronous request then perform any necessary
}
try_exit: NOTHING;
- } finally {
+ } _SEH2_FINALLY {
//
// Perform final cleanup on the IoRuns if necessary.
CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
}
- }
+ } _SEH2_END;
return Status;
}
\f
+
+_Requires_lock_held_(_Global_critical_region_)
NTSTATUS
CdNonCachedXARead (
- IN PIRP_CONTEXT IrpContext,
- IN PFCB Fcb,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount
)
/*++
ULONG UserBufferOffset = 0;
LONGLONG CurrentOffset = StartingOffset;
ULONG RemainingByteCount = ByteCount;
- ULONG ThisByteCount;
+ ULONG ThisByteCount = 0;
+ ULONG Address = 0;
BOOLEAN TryingYellowbookMode2 = FALSE;
if (IrpContext->Irp->MdlAddress == NULL) {
- CdCreateUserMdl( IrpContext, ByteCount, TRUE );
+ CdCreateUserMdl( IrpContext, ByteCount, TRUE, IoWriteAccess );
}
//
// Use a try-finally to perform the final cleanup.
//
- try {
+ _SEH2_TRY {
//
// If the initial offset lies within the RIFF header then copy the
PAUDIO_PLAY_HEADER AudioPlayHeader;
PTRACK_DATA TrackData;
- ULONG SectorCount;
AudioPlayHeader = (PAUDIO_PLAY_HEADER) &LocalRiffHeader;
TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber];
AudioPlayHeader->DiskID = Fcb->Vcb->Vpb->SerialNumber;
AudioPlayHeader->TrackNumber = TrackData->TrackNumber;
- //
- // TOC contains MSF (Minute/Second/Frame) addresses. This is very
- // arcane, and we wind up having to bias around by the size of the
- // leadins and other such silliness to find real live sector addrs.
//
// One frame == One sector.
// One second == 75 frames (winds up being a 44.1khz sample)
//
-
- //
- // Fill in the address and length fields.
+ // Note: LBN 0 == 0:2:0 (MSF)
//
-
- AudioPlayHeader->TrackAddress[2] = TrackData->Address[1];
- AudioPlayHeader->TrackAddress[1] = TrackData->Address[2];
- AudioPlayHeader->TrackAddress[0] = TrackData->Address[3];
-
- AudioPlayHeader->StartingSector = TrackData->Address[3];
- AudioPlayHeader->StartingSector += (TrackData->Address[2] * 75);
- AudioPlayHeader->StartingSector += (TrackData->Address[1] * 60 * 75);
-
+
//
- // Subtract 2 seconds for the block number.
+ // Fill in the address (both MSF and Lbn format) and length fields.
//
-
- AudioPlayHeader->StartingSector -= 150;
+
+ SwapCopyUchar4( &Address, TrackData->Address);
+ CdLbnToMmSsFf( Address, AudioPlayHeader->TrackAddress);
+
+ SwapCopyUchar4( &AudioPlayHeader->StartingSector, TrackData->Address);
//
// Go to the next track and find the starting point.
TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber + 1];
- AudioPlayHeader->SectorCount = TrackData->Address[3];
- AudioPlayHeader->SectorCount += (TrackData->Address[2] * 75);
- AudioPlayHeader->SectorCount += (TrackData->Address[1] * 60 * 75);
-
- //
- // Bias the sector count by 2 seconds.
- // Check that the offset is at least two seconds.
- //
-
- if (AudioPlayHeader->SectorCount < 150) {
-
- AudioPlayHeader->SectorCount = 0;
-
- } else {
-
- AudioPlayHeader->SectorCount -= 150;
- }
+ SwapCopyUchar4( &AudioPlayHeader->SectorCount, TrackData->Address);
//
// Now compute the difference. If there is an error then use
}
//
- // Use the sector count to determine the MSF length.
+ // Use the sector count to determine the MSF length. Bias by 150 to make
+ // it an "lbn" since the conversion routine corrects for Lbn 0 == 0:2:0;
//
- SectorCount = AudioPlayHeader->SectorCount;
-
- AudioPlayHeader->TrackLength[0] = (UCHAR) (SectorCount % 75);
- SectorCount /= 75;
-
- AudioPlayHeader->TrackLength[1] = (UCHAR) (SectorCount % 60);
- SectorCount /= 60;
-
- AudioPlayHeader->TrackLength[2] = (UCHAR) (SectorCount % 60);
+ Address = AudioPlayHeader->SectorCount - 150;
+ CdLbnToMmSsFf( Address, AudioPlayHeader->TrackLength);
ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
} else {
- ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE ));
+ NT_ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE ));
RiffHeader = &LocalRiffHeader;
KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
try_exit: NOTHING;
- } finally {
+ } _SEH2_FINALLY {
//
// Perform final cleanup on the IoRuns if necessary.
CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
}
+ } _SEH2_END;
+
+ return Status;
+}
+
+_Requires_lock_held_(_Global_critical_region_)
+NTSTATUS
+CdVolumeDasdWrite (
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the non-cached writes to 'cooked' sectors (2048 bytes
+ per sector). This is done by filling the IoRun for the desired request
+ and send it down to the device.
+
+Arguments:
+
+ Fcb - Fcb representing the file to read.
+
+ StartingOffset - Logical offset in the file to read from.
+
+ ByteCount - Number of bytes to read.
+
+Return Value:
+
+ NTSTATUS - Status indicating the result of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_RUN IoRun;
+
+ PAGED_CODE();
+
+ //
+ // We want to make sure the user's buffer is locked in all cases.
+ //
+
+ CdLockUserBuffer( IrpContext, ByteCount, IoReadAccess );
+
+ //
+ // The entire Io can be contained in a single run, just pass
+ // the Io down to the driver. Send the driver down
+ // and wait on the result if this is synchronous.
+ //
+
+ RtlZeroMemory( &IoRun, sizeof( IoRun ) );
+
+ IoRun.DiskOffset = StartingOffset;
+ IoRun.DiskByteCount = ByteCount;
+
+ CdSingleAsync( IrpContext, &IoRun, Fcb );
+
+ //
+ // Wait if we are synchronous, otherwise return
+ //
+
+ if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
+
+ CdWaitSync( IrpContext );
+
+ Status = IrpContext->Irp->IoStatus.Status;
+
+ //
+ // Our completion routine will free the Io context but
+ // we do want to return STATUS_PENDING.
+ //
+
+ } else {
+
+ ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
+ Status = STATUS_PENDING;
}
return Status;
}
+
\f
BOOLEAN
CdReadSectors (
- IN PIRP_CONTEXT IrpContext,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN BOOLEAN ReturnError,
- IN OUT PVOID Buffer,
- IN PDEVICE_OBJECT TargetDeviceObject
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount,
+ _In_ BOOLEAN ReturnError,
+ _Out_writes_bytes_(ByteCount) PVOID Buffer,
+ _In_ PDEVICE_OBJECT TargetDeviceObject
)
/*++
\f
NTSTATUS
CdCreateUserMdl (
- IN PIRP_CONTEXT IrpContext,
- IN ULONG BufferLength,
- IN BOOLEAN RaiseOnError
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ ULONG BufferLength,
+ _In_ BOOLEAN RaiseOnError,
+ _In_ LOCK_OPERATION Operation
)
/*++
RaiseOnError - Indicates if our caller wants this routine to raise on
an error condition.
+ Operation - IoWriteAccess or IoReadAccess
+
Return Value:
NTSTATUS - Status from this routine. Error status only returned if
PAGED_CODE();
+ UNREFERENCED_PARAMETER( Operation );
+ UNREFERENCED_PARAMETER( IrpContext );
+
ASSERT_IRP_CONTEXT( IrpContext );
ASSERT_IRP( IrpContext->Irp );
- ASSERT( IrpContext->Irp->MdlAddress == NULL );
+ NT_ASSERT( IrpContext->Irp->MdlAddress == NULL );
//
// Allocate the Mdl, and Raise if we fail.
// deallocate the Mdl and return the appropriate "expected" status.
//
- try {
+ _SEH2_TRY {
MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
Status = STATUS_SUCCESS;
- } except(EXCEPTION_EXECUTE_HANDLER) {
+#ifdef _MSC_VER
+#pragma warning(suppress: 6320)
+#endif
+ } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
- Status = GetExceptionCode();
+ Status = _SEH2_GetExceptionCode();
IoFreeMdl( Mdl );
IrpContext->Irp->MdlAddress = NULL;
Status = STATUS_INVALID_USER_BUFFER;
}
- }
+ } _SEH2_END;
}
//
\f
NTSTATUS
-CdPerformDevIoCtrl (
- IN PIRP_CONTEXT IrpContext,
- IN ULONG IoControlCode,
- IN PDEVICE_OBJECT Device,
- OUT PVOID OutputBuffer OPTIONAL,
- IN ULONG OutputBufferLength,
- IN BOOLEAN InternalDeviceIoControl,
- IN BOOLEAN OverrideVerify,
- OUT PIO_STATUS_BLOCK Iosb OPTIONAL
+CdPerformDevIoCtrlEx (
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ ULONG IoControlCode,
+ _In_ PDEVICE_OBJECT Device,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ ULONG InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ ULONG OutputBufferLength,
+ _In_ BOOLEAN InternalDeviceIoControl,
+ _In_ BOOLEAN OverrideVerify,
+ _Out_opt_ PIO_STATUS_BLOCK Iosb
)
/*++
PAGED_CODE();
+ UNREFERENCED_PARAMETER( IrpContext );
+
//
// Check if the user gave us an Iosb.
//
Irp = IoBuildDeviceIoControlRequest( IoControlCode,
Device,
- NULL,
- 0,
+ InputBuffer,
+ InputBufferLength,
OutputBuffer,
OutputBufferLength,
InternalDeviceIoControl,
Status = IosbToUse->Status;
}
- ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
+ NT_ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
return Status;
}
+
+NTSTATUS
+FASTCALL
+CdPerformDevIoCtrl (
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ ULONG IoControlCode,
+ _In_ PDEVICE_OBJECT Device,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ ULONG OutputBufferLength,
+ _In_ BOOLEAN InternalDeviceIoControl,
+ _In_ BOOLEAN OverrideVerify,
+ _Out_opt_ PIO_STATUS_BLOCK Iosb
+ )
+{
+ PAGED_CODE();
+
+ return CdPerformDevIoCtrlEx( IrpContext,
+ IoControlCode,
+ Device,
+ NULL,
+ 0,
+ OutputBuffer,
+ OutputBufferLength,
+ InternalDeviceIoControl,
+ OverrideVerify,
+ Iosb);
+}
+
+
\f
//
// Local support routine
//
+_Requires_lock_held_(_Global_critical_region_)
BOOLEAN
CdPrepareBuffers (
- IN PIRP_CONTEXT IrpContext,
- IN PIRP Irp,
- IN PFCB Fcb,
- IN PVOID UserBuffer,
- IN ULONG UserBufferOffset,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN PIO_RUN IoRuns,
- IN PULONG RunCount,
- IN PULONG ThisByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIRP Irp,
+ _In_ PFCB Fcb,
+ _In_reads_bytes_(ByteCount) PVOID UserBuffer,
+ _In_ ULONG UserBufferOffset,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount,
+ _Out_ PIO_RUN IoRuns,
+ _Out_ PULONG RunCount,
+ _Out_ PULONG ThisByteCount
)
/*++
PVOID CurrentUserBuffer = UserBuffer;
ULONG CurrentUserBufferOffset = UserBufferOffset;
- PVOID ScratchUserBuffer = UserBuffer;
- ULONG ScratchUserBufferOffset = UserBufferOffset;
-
//
// The following is the next contiguous bytes on the disk to
// transfer. Read from the allocation package.
//
- LONGLONG DiskOffset;
- ULONG CurrentByteCount;
+ LONGLONG DiskOffset = 0;
+ ULONG CurrentByteCount = RemainingByteCount;
PAGED_CODE();
//
// Byte count is a multiple of 2048 (Length of transfer)
//
- // Current buffer offset is also on a 2048 byte boundary.
- //
// If the ByteCount is at least one sector then do the
// unaligned transfer only for the tail. We can use the
// user's buffer for the aligned portion.
//
if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) ||
- FlagOn( CurrentUserBufferOffset, SECTOR_MASK ) ||
(FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) &&
(CurrentByteCount < SECTOR_SIZE))) {
+ NT_ASSERT( SafeNodeType(Fcb) != CDFS_NTC_FCB_INDEX);
+
//
// If we can't wait then raise.
//
ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset );
//
- // Check if we can use a free portion of the user's buffer.
- // If we can copy the bytes to an earlier portion of the
- // buffer then read into that location and slide the bytes
- // up.
- //
- // We can use the user's buffer if:
- //
- // The temporary location in the buffer is before the
- // final destination.
- //
- // There is at least one sector of data to read.
+ // We need to allocate an auxilary buffer for the next sector.
+ // Read up to a page containing the partial data.
//
- if ((ScratchUserBufferOffset + ThisIoRun->TransferBufferOffset < CurrentUserBufferOffset) &&
- (ThisIoRun->TransferBufferOffset + CurrentByteCount >= SECTOR_SIZE)) {
+ ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
- ThisIoRun->DiskByteCount = SectorTruncate( ThisIoRun->TransferBufferOffset + CurrentByteCount );
- CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
- ThisIoRun->TransferByteCount = CurrentByteCount;
+ if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
- //
- // Point to the user's buffer and Mdl for this transfer.
- //
+ ThisIoRun->DiskByteCount = PAGE_SIZE;
+ }
- ThisIoRun->TransferBuffer = ScratchUserBuffer;
- ThisIoRun->TransferMdl = Irp->MdlAddress;
- ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
- ScratchUserBufferOffset,
- PVOID );
+ if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
- ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
- ThisIoRun->DiskByteCount,
- PVOID );
+ CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
+ }
- ScratchUserBufferOffset += ThisIoRun->DiskByteCount;
+ ThisIoRun->TransferByteCount = CurrentByteCount;
//
- // Otherwise we need to allocate an auxilary buffer for the next sector.
+ // Allocate a buffer for the non-aligned transfer.
//
- } else {
-
- //
- // Read up to a page containing the partial data
- //
-
- ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
-
- if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
-
- ThisIoRun->DiskByteCount = PAGE_SIZE;
- }
-
- if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
-
- CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
- }
-
- ThisIoRun->TransferByteCount = CurrentByteCount;
-
- //
- // Allocate a buffer for the non-aligned transfer.
- //
-
- ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
-
- //
- // Allocate and build the Mdl to describe this buffer.
- //
+ ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
- ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
- PAGE_SIZE,
- FALSE,
- FALSE,
- NULL );
+ //
+ // Allocate and build the Mdl to describe this buffer.
+ //
- ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
+ ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
+ PAGE_SIZE,
+ FALSE,
+ FALSE,
+ NULL );
- if (ThisIoRun->TransferMdl == NULL) {
+ ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
- IrpContext->Irp->IoStatus.Information = 0;
- CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
- }
+ if (ThisIoRun->TransferMdl == NULL) {
- MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
+ IrpContext->Irp->IoStatus.Information = 0;
+ CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
}
+ MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
+
//
// Remember we found an unaligned transfer.
//
ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
CurrentUserBufferOffset,
PVOID );
-
- ScratchUserBuffer = Add2Ptr( CurrentUserBuffer,
- CurrentByteCount,
- PVOID );
-
- ScratchUserBufferOffset += CurrentByteCount;
}
//
// Local support routine
//
+_Requires_lock_held_(_Global_critical_region_)
VOID
CdPrepareXABuffers (
- IN PIRP_CONTEXT IrpContext,
- IN PIRP Irp,
- IN PFCB Fcb,
- IN PVOID UserBuffer,
- IN ULONG UserBufferOffset,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN PIO_RUN IoRuns,
- IN PULONG RunCount,
- IN PULONG ThisByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIRP Irp,
+ _In_ PFCB Fcb,
+ _In_reads_bytes_(ByteCount) PVOID UserBuffer,
+ _In_ ULONG UserBufferOffset,
+ _In_ LONGLONG StartingOffset,
+ _In_ ULONG ByteCount,
+ _Out_ PIO_RUN IoRuns,
+ _Out_ PULONG RunCount,
+ _Out_ PULONG ThisByteCount
)
/*++
PVOID CurrentUserBuffer = UserBuffer;
ULONG CurrentUserBufferOffset = UserBufferOffset;
- PVOID ScratchUserBuffer = UserBuffer;
- ULONG ScratchUserBufferOffset = UserBufferOffset;
- BOOLEAN RoundScratchBuffer = TRUE;
-
//
// The following is the next contiguous bytes on the disk to
// transfer. These are represented by cooked byte offset and length.
// We also compute the number of raw bytes in the current transfer.
//
- LONGLONG DiskOffset;
- ULONG CurrentCookedByteCount;
+ LONGLONG DiskOffset = 0;
+ ULONG CurrentCookedByteCount = 0;
ULONG CurrentRawByteCount;
PAGED_CODE();
CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
+#ifdef _MSC_VER
+#pragma prefast( suppress: __WARNING_RESULTOFSHIFTCASTTOLARGERSIZE, "This is fine beacuse raw sector size > sector shift" )
+#endif
CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
PerformedCopy = FALSE;
*RunCount += 1;
- //
- // Round the scratch buffer up to a sector boundary for alignment.
- //
-
- if (RoundScratchBuffer) {
-
- if (SectorOffset( ScratchUserBuffer ) != 0) {
-
- CurrentRawByteCount = SECTOR_SIZE - SectorOffset( ScratchUserBuffer );
-
- ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
- CurrentRawByteCount,
- PVOID );
-
- ScratchUserBufferOffset += CurrentRawByteCount;
- }
-
- RoundScratchBuffer = FALSE;
- }
-
//
// Initialize the current position in the IoRuns array. Find the
// eventual destination in the user's buffer for this portion of the transfer.
ThisIoRun -= 1;
//
- // Remember that we performed a copy operation and update
- // the next available position in the scratch buffer.
+ // Remember that we performed a copy operation.
//
PerformedCopy = TRUE;
- ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
- CurrentRawByteCount,
- PVOID );
-
- ScratchUserBufferOffset += CurrentRawByteCount;
-
CurrentCookedByteCount = SECTOR_SIZE;
- //
- // Set the flag indicating we want to round the scratch buffer
- // to a sector boundary.
- //
-
- RoundScratchBuffer = TRUE;
-
} else {
//
//
if ((RawSectorOffset == 0) &&
- (ScratchUserBufferOffset <= CurrentUserBufferOffset) &&
- (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
+ (RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
//
// We can use the scratch buffer. We must ensure we don't send down reads
// Now make sure we are within the page transfer limit.
//
- while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
+ while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
Fcb->Vcb->MaximumPhysicalPages ) {
CurrentRawByteCount -= RAW_SECTOR_SIZE;
// account of the fact that we must read in whole raw sector multiples.
//
- while ( RawSectorAlign( CurrentRawByteCount) >
- (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount) ) {
+ while (RawSectorAlign( CurrentRawByteCount) > RemainingRawByteCount) {
CurrentRawByteCount -= RAW_SECTOR_SIZE;
CurrentCookedByteCount -= SECTOR_SIZE;
ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
- //
- // Store the number of bytes which we actually care about from this transfer
- //
-
- ThisIoRun->TransferByteCount = CurrentRawByteCount;
-
//
// Point to the user's buffer and Mdl for this transfer.
//
- ThisIoRun->TransferBuffer = ScratchUserBuffer;
+ ThisIoRun->TransferBuffer = CurrentUserBuffer;
ThisIoRun->TransferMdl = Irp->MdlAddress;
ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
- ScratchUserBufferOffset,
+ CurrentUserBufferOffset,
PVOID);
- //
- // Update the scratch buffer pointer. Note that since the underlying
- // driver stack will always transfer in multiples of raw sectors,
- // we must round up here rather than simply advancing by the length of the
- // of the data which we actually care about.
- //
-
- ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
- RawSectorAlign( CurrentRawByteCount),
- PVOID );
-
- ScratchUserBufferOffset += RawSectorAlign( CurrentRawByteCount);
-
- //
- // Set the flag indicating we want to round the scratch buffer
- // to a cooked sector boundary.
- //
-
- RoundScratchBuffer = TRUE;
} else {
BOOLEAN
CdFinishBuffers (
- IN PIRP_CONTEXT IrpContext,
- IN PIO_RUN IoRuns,
- IN ULONG RunCount,
- IN BOOLEAN FinalCleanup,
- IN BOOLEAN SaveXABuffer
+ _In_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIO_RUN IoRuns,
+ _In_ ULONG RunCount,
+ _In_ BOOLEAN FinalCleanup,
+ _In_ BOOLEAN SaveXABuffer
)
/*++
if (!FinalCleanup) {
- //
- // If we are shifting in the user's buffer then use
- // MoveMemory.
- //
-
- if (ThisIoRun->TransferMdl == IrpContext->Irp->MdlAddress) {
-
- RtlMoveMemory( ThisIoRun->UserBuffer,
- Add2Ptr( ThisIoRun->TransferBuffer,
- ThisIoRun->TransferBufferOffset,
- PVOID ),
- ThisIoRun->TransferByteCount );
-
- } else {
-
- RtlCopyMemory( ThisIoRun->UserBuffer,
- Add2Ptr( ThisIoRun->TransferBuffer,
- ThisIoRun->TransferBufferOffset,
- PVOID ),
- ThisIoRun->TransferByteCount );
- }
+ RtlCopyMemory( ThisIoRun->UserBuffer,
+ Add2Ptr( ThisIoRun->TransferBuffer,
+ ThisIoRun->TransferBufferOffset,
+ PVOID ),
+ ThisIoRun->TransferByteCount );
FlushIoBuffers = TRUE;
}
return FlushIoBuffers;
}
-\f
-//
-// Local support routine
-//
+// Tell prefast this is a completion routine.
+IO_COMPLETION_ROUTINE CdSyncCompletionRoutine;
-VOID
-CdMultipleAsync (
- IN PIRP_CONTEXT IrpContext,
- IN ULONG RunCount,
- IN PIO_RUN IoRuns
+NTSTATUS
+NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
+CdSyncCompletionRoutine (
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Contxt
)
/*++
Routine Description:
- This routine first does the initial setup required of a Master IRP that is
- going to be completed using associated IRPs. This routine should not
- be used if only one async request is needed, instead the single read
- async routines should be called.
+ Completion routine for synchronizing back to dispatch.
- A context parameter is initialized, to serve as a communications area
- between here and the common completion routine.
+Arguments:
- Next this routine reads or writes one or more contiguous sectors from
- a device asynchronously, and is used if there are multiple reads for a
- master IRP. A completion routine is used to synchronize with the
- completion of all of the I/O requests started by calls to this routine.
+ Contxt - pointer to KEVENT.
- Also, prior to calling this routine the caller must initialize the
- IoStatus field in the Context, with the correct success status and byte
+Return Value:
+
+ STATUS_MORE_PROCESSING_REQUIRED
+
+--*/
+
+{
+ PKEVENT Event = (PKEVENT)Contxt;
+ _Analysis_assume_(Contxt != NULL);
+
+ UNREFERENCED_PARAMETER( Irp );
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ KeSetEvent( Event, 0, FALSE );
+
+ //
+ // We don't want IO to get our IRP and free it.
+ //
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+_Requires_lock_held_(_Global_critical_region_)
+VOID
+CdFreeDirCache (
+ _In_ PIRP_CONTEXT IrpContext
+ )
+
+/*++
+
+Routine Description:
+
+ Safely frees the sector cache buffer.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ if (NULL != IrpContext->Vcb->SectorCacheBuffer) {
+
+ CdAcquireCacheForUpdate( IrpContext);
+ CdFreePool( &IrpContext->Vcb->SectorCacheBuffer);
+ CdReleaseCache( IrpContext);
+ }
+}
+
+_Requires_lock_held_(_Global_critical_region_)
+BOOLEAN
+CdReadDirDataThroughCache (
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIO_RUN Run
+ )
+
+/*++
+
+Routine Description:
+
+ Reads blocks through the sector cache. If the data is present, then it
+ is copied from memory. If not present, one of the cache chunks will be
+ replaced with a chunk containing the requested region, and the data
+ copied from there.
+
+ Only intended for reading *directory* blocks, for the purpose of pre-caching
+ directory information, by reading a chunk of blocks which hopefully contains
+ other directory blocks, rather than just the (usually) single block requested.
+
+Arguments:
+
+ Run - description of extent required, and buffer to read into.
+
+Return Value:
+
+ None. Raises on error.
+
+--*/
+
+{
+ PVCB Vcb = IrpContext->Vcb;
+ ULONG Lbn = SectorsFromLlBytes( Run->DiskOffset);
+ ULONG Remaining = SectorsFromBytes( Run->DiskByteCount);
+ PUCHAR UserBuffer = Run->TransferBuffer;
+
+ NTSTATUS Status;
+ ULONG Found;
+ ULONG BufferSectorOffset;
+ ULONG StartBlock;
+ ULONG EndBlock;
+ ULONG Blocks;
+
+ PIO_STACK_LOCATION IrpSp;
+ IO_STATUS_BLOCK Iosb;
+
+ PTRACK_DATA TrackData;
+
+#if DBG
+ BOOLEAN JustRead = FALSE;
+#endif
+
+ ULONG Index;
+ PCD_SECTOR_CACHE_CHUNK Buffer;
+ BOOLEAN Result = FALSE;
+
+ PAGED_CODE();
+
+ CdAcquireCacheForRead( IrpContext);
+
+ _SEH2_TRY {
+
+ //
+ // Check the cache hasn't gone away due to volume verify failure (which
+ // is the *only* reason it'll go away). If this is the case we raise
+ // the same error any I/O would return if the cache weren't here.
+ //
+
+ if (NULL == Vcb->SectorCacheBuffer) {
+
+ CdRaiseStatus( IrpContext, STATUS_VERIFY_REQUIRED);
+ }
+
+ while (Remaining) {
+
+ Buffer = NULL;
+
+ //
+ // Look to see if any portion is currently cached.
+ //
+
+ for (Index = 0; Index < CD_SEC_CACHE_CHUNKS; Index++) {
+
+ if ((Vcb->SecCacheChunks[ Index].BaseLbn != -1) &&
+ (Vcb->SecCacheChunks[ Index].BaseLbn <= Lbn) &&
+ ((Vcb->SecCacheChunks[ Index].BaseLbn + CD_SEC_CHUNK_BLOCKS) > Lbn)) {
+
+ Buffer = &Vcb->SecCacheChunks[ Index];
+ break;
+ }
+ }
+
+ //
+ // If we found any, copy it out and continue.
+ //
+
+ if (NULL != Buffer) {
+
+ BufferSectorOffset = Lbn - Buffer->BaseLbn;
+ Found = Min( CD_SEC_CHUNK_BLOCKS - BufferSectorOffset, Remaining);
+
+ RtlCopyMemory( UserBuffer,
+ Buffer->Buffer + BytesFromSectors( BufferSectorOffset),
+ BytesFromSectors( Found));
+
+ Remaining -= Found;
+ UserBuffer += BytesFromSectors( Found);
+ Lbn += Found;
+#if DBG
+ //
+ // Update stats. Don't count a hit if we've just read the data in.
+ //
+
+ if (!JustRead) {
+
+ InterlockedIncrement( (LONG*)&Vcb->SecCacheHits);
+ }
+
+ JustRead = FALSE;
+#endif
+ continue;
+ }
+
+ //
+ // Missed the cache, so we need to read a new chunk. Take the cache
+ // resource exclusive while we do so.
+ //
+
+ CdReleaseCache( IrpContext);
+ CdAcquireCacheForUpdate( IrpContext);
+#if DBG
+ Vcb->SecCacheMisses += 1;
+#endif
+ //
+ // Select the chunk to replace and calculate the start block of the
+ // chunk to cache. We cache blocks which start on Lbns aligned on
+ // multiples of chunk size, treating block 16 (VRS start) as block
+ // zero.
+ //
+
+ Buffer = &Vcb->SecCacheChunks[ Vcb->SecCacheLRUChunkIndex];
+
+ StartBlock = Lbn - ((Lbn - 16) % CD_SEC_CHUNK_BLOCKS);
+
+ //
+ // Make sure we don't try and read past end of the last track.
+ //
+
+#ifdef __REACTOS__
+ if (Vcb->CdromToc) {
+#endif
+ TrackData = &Vcb->CdromToc->TrackData[(Vcb->CdromToc->LastTrack - Vcb->CdromToc->FirstTrack + 1)];
+
+ SwapCopyUchar4( &EndBlock, &TrackData->Address );
+
+ Blocks = EndBlock - StartBlock;
+
+ if (Blocks > CD_SEC_CHUNK_BLOCKS) {
+
+ Blocks = CD_SEC_CHUNK_BLOCKS;
+ }
+#ifdef __REACTOS__
+ } else {
+ // HACK!!!!!!!! Might cause reads to overrun the end of the partition, no idea what consequences that can have.
+ Blocks = CD_SEC_CHUNK_BLOCKS;
+ }
+#endif
+
+ if ((0 == Blocks) || (Lbn < 16)) {
+
+ CdRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER);
+ }
+
+ //
+ // Now build / send the read request.
+ //
+
+ IoReuseIrp( Vcb->SectorCacheIrp, STATUS_SUCCESS);
+
+ KeClearEvent( &Vcb->SectorCacheEvent);
+ Vcb->SectorCacheIrp->Tail.Overlay.Thread = PsGetCurrentThread();
+
+ //
+ // Get a pointer to the stack location of the first driver which will be
+ // invoked. This is where the function codes and the parameters are set.
+ //
+
+ IrpSp = IoGetNextIrpStackLocation( Vcb->SectorCacheIrp);
+ IrpSp->MajorFunction = (UCHAR) IRP_MJ_READ;
+
+ //
+ // Build an MDL to describe the buffer.
+ //
+
+ IoAllocateMdl( Buffer->Buffer,
+ BytesFromSectors( Blocks),
+ FALSE,
+ FALSE,
+ Vcb->SectorCacheIrp);
+
+ if (NULL == Vcb->SectorCacheIrp->MdlAddress) {
+
+ IrpContext->Irp->IoStatus.Information = 0;
+ CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // We're reading/writing into the block cache (paged pool). Lock the
+ // pages and update the MDL with physical page information.
+ //
+
+ _SEH2_TRY {
+
+ MmProbeAndLockPages( Vcb->SectorCacheIrp->MdlAddress,
+ KernelMode,
+ (LOCK_OPERATION) IoWriteAccess );
+ }
+#ifdef _MSC_VER
+#pragma warning(suppress: 6320)
+#endif
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+
+ IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress );
+ Vcb->SectorCacheIrp->MdlAddress = NULL;
+ } _SEH2_END;
+
+ if (NULL == Vcb->SectorCacheIrp->MdlAddress) {
+
+ CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
+ }
+
+ //
+ // Reset the BaseLbn as we can't trust this Buffer's data until the request
+ // is successfully completed.
+ //
+
+ Buffer->BaseLbn = (ULONG)-1;
+
+ IrpSp->Parameters.Read.Length = BytesFromSectors( Blocks);
+ IrpSp->Parameters.Read.ByteOffset.QuadPart = LlBytesFromSectors( StartBlock);
+
+ IoSetCompletionRoutine( Vcb->SectorCacheIrp,
+ CdSyncCompletionRoutine,
+ &Vcb->SectorCacheEvent,
+ TRUE,
+ TRUE,
+ TRUE );
+
+ Vcb->SectorCacheIrp->UserIosb = &Iosb;
+
+ Status = IoCallDriver( Vcb->TargetDeviceObject, Vcb->SectorCacheIrp );
+
+ if (STATUS_PENDING == Status) {
+
+
+ (VOID)KeWaitForSingleObject( &Vcb->SectorCacheEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ Status = Vcb->SectorCacheIrp->IoStatus.Status;
+ }
+
+ Vcb->SectorCacheIrp->UserIosb = NULL;
+
+ //
+ // Unlock the pages and free the MDL.
+ //
+
+ MmUnlockPages( Vcb->SectorCacheIrp->MdlAddress );
+ IoFreeMdl( Vcb->SectorCacheIrp->MdlAddress );
+ Vcb->SectorCacheIrp->MdlAddress = NULL;
+
+ if (!NT_SUCCESS( Status )) {
+
+ try_leave( Status );
+ }
+
+ //
+ // Update the buffer information, and drop the cache resource to shared
+ // to allow in reads.
+ //
+
+ Buffer->BaseLbn = StartBlock;
+ Vcb->SecCacheLRUChunkIndex = (Vcb->SecCacheLRUChunkIndex + 1) % CD_SEC_CACHE_CHUNKS;
+
+ CdConvertCacheToShared( IrpContext);
+#if DBG
+ JustRead = TRUE;
+#endif
+ }
+
+ Result = TRUE;
+ }
+ _SEH2_FINALLY {
+
+ CdReleaseCache( IrpContext);
+ } _SEH2_END;
+
+ return Result;
+}
+
+
+//
+// Local support routine
+//
+
+_Requires_lock_held_(_Global_critical_region_)
+VOID
+CdMultipleAsync (
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ ULONG RunCount,
+ _Inout_ PIO_RUN IoRuns
+ )
+
+/*++
+
+Routine Description:
+
+ This routine first does the initial setup required of a Master IRP that is
+ going to be completed using associated IRPs. This routine should not
+ be used if only one async request is needed, instead the single read
+ async routines should be called.
+
+ A context parameter is initialized, to serve as a communications area
+ between here and the common completion routine.
+
+ Next this routine reads or writes one or more contiguous sectors from
+ a device asynchronously, and is used if there are multiple reads for a
+ master IRP. A completion routine is used to synchronize with the
+ completion of all of the I/O requests started by calls to this routine.
+
+ Also, prior to calling this routine the caller must initialize the
+ IoStatus field in the Context, with the correct success status and byte
count which are expected if all of the parallel transfers complete
successfully. After return this status will be unchanged if all requests
were, in fact, successful. However, if one or more errors occur, the
PIRP Irp;
PIRP MasterIrp;
ULONG UnwindRunCount;
+ BOOLEAN UseSectorCache;
PAGED_CODE();
CompletionRoutine = CdMultiAsyncCompletionRoutine;
}
+ //
+ // For directories, use the sector cache.
+ //
+
+ if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
+ (NULL != Fcb->Vcb->SectorCacheBuffer) &&
+ (VcbMounted == IrpContext->Vcb->VcbCondition)) {
+
+ UseSectorCache = TRUE;
+ }
+ else {
+
+ UseSectorCache = FALSE;
+ }
+
//
// Initialize some local variables.
//
UnwindRunCount < RunCount;
UnwindRunCount += 1) {
+ if (UseSectorCache) {
+
+ if (!CdReadDirDataThroughCache( IrpContext, &IoRuns[ UnwindRunCount])) {
+
+ //
+ // Turn off using directory cache and restart all over again.
+ //
+
+ UseSectorCache = FALSE;
+ UnwindRunCount = 0;
+ }
+
+ continue;
+ }
+
//
// Create an associated IRP, making sure there is one stack entry for
// us, as well.
IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
}
+ //
+ // If we used the cache, we're done.
+ //
+
+ if (UseSectorCache) {
+
+ if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
+
+ IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
+ KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE );
+ }
+
+ return;
+ }
+
//
// We only need to set the associated IRP count in the master irp to
// make it a master IRP. But we set the count to one more than our
MasterIrp->AssociatedIrp.IrpCount = 1;
+ //
+ // If we (FS) acquired locks, transition the lock owners to an object, since
+ // when we return this thread could go away before request completion, and
+ // the resource package may otherwise try to boost priority, etc.
+ //
+
+ if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ) &&
+ FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
+
+ NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() );
+
+ IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3;
+
+ ExSetResourceOwnerPointer( IrpContext->IoContext->Resource,
+ (PVOID)IrpContext->IoContext->ResourceThreadId );
+ }
+
//
// Now that all the dangerous work is done, issue the Io requests
//
Irp = IoRuns[UnwindRunCount].SavedIrp;
IoRuns[UnwindRunCount].SavedIrp = NULL;
- //
- // If IoCallDriver returns an error, it has completed the Irp
- // and the error will be caught by our completion routines
- // and dealt with as a normal IO error.
- //
+ if (NULL != Irp) {
+
+ //
+ // If IoCallDriver returns an error, it has completed the Irp
+ // and the error will be caught by our completion routines
+ // and dealt with as a normal IO error.
+ //
- (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
+ (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
+ }
}
-
- return;
}
\f
VOID
CdMultipleXAAsync (
- IN PIRP_CONTEXT IrpContext,
- IN ULONG RunCount,
- IN PIO_RUN IoRuns,
- IN PRAW_READ_INFO RawReads,
- IN TRACK_MODE_TYPE TrackMode
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ ULONG RunCount,
+ _Inout_ PIO_RUN IoRuns,
+ _In_ PRAW_READ_INFO RawReads,
+ _In_ TRACK_MODE_TYPE TrackMode
)
/*++
// must be a multiple of sector size
//
- ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
+ NT_ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
// Local support routine
//
+_Requires_lock_held_(_Global_critical_region_)
VOID
CdSingleAsync (
- IN PIRP_CONTEXT IrpContext,
- IN LONGLONG ByteOffset,
- IN ULONG ByteCount
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PIO_RUN Run,
+ _In_ PFCB Fcb
)
/*++
PAGED_CODE();
+ //
+ // For directories, look in the sector cache,
+ //
+
+ if ((SafeNodeType( Fcb) == CDFS_NTC_FCB_INDEX) &&
+ (NULL != Fcb->Vcb->SectorCacheBuffer) &&
+ (VcbMounted == IrpContext->Vcb->VcbCondition)) {
+
+ if (CdReadDirDataThroughCache( IrpContext, Run )) {
+
+ if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
+
+ IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
+ KeSetEvent( &IrpContext->IoContext->SyncEvent, 0, FALSE );
+ }
+
+ return;
+ }
+ }
+
//
// Set up things according to whether this is truely async.
//
} else {
CompletionRoutine = CdSingleAsyncCompletionRoutine;
+
+ //
+ // If we (FS) acquired locks, transition the lock owners to an object, since
+ // when we return this thread could go away before request completion, and
+ // the resource package may otherwise try to boost priority, etc.
+ //
+
+ if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL )) {
+
+ NT_ASSERT( IrpContext->IoContext->ResourceThreadId == (ERESOURCE_THREAD)PsGetCurrentThread() );
+
+ IrpContext->IoContext->ResourceThreadId = ((ULONG_PTR)IrpContext->IoContext) | 3;
+
+ ExSetResourceOwnerPointer( IrpContext->IoContext->Resource,
+ (PVOID)IrpContext->IoContext->ResourceThreadId );
+ }
}
//
// Setup the Stack location to do a read from the disk driver.
//
- IrpSp->MajorFunction = IRP_MJ_READ;
- IrpSp->Parameters.Read.Length = ByteCount;
- IrpSp->Parameters.Read.ByteOffset.QuadPart = ByteOffset;
+ IrpSp->MajorFunction = IrpContext->MajorFunction;
+ IrpSp->Parameters.Read.Length = Run->DiskByteCount;
+ IrpSp->Parameters.Read.ByteOffset.QuadPart = Run->DiskOffset;
//
// Issue the Io request
//
(VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
-
- //
- // And return to our caller
- //
-
- return;
}
\f
VOID
CdWaitSync (
- IN PIRP_CONTEXT IrpContext
+ _In_ PIRP_CONTEXT IrpContext
)
/*++
{
PAGED_CODE();
- KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
+
+ (VOID)KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
Executive,
KernelMode,
FALSE,
NULL );
KeClearEvent( &IrpContext->IoContext->SyncEvent );
-
- return;
}
\f
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CdMultiSyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
)
/*++
{
PCD_IO_CONTEXT IoContext = Context;
+ _Analysis_assume_(Context != NULL);
AssertVerifyDeviceIrp( Irp );
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CdMultiAsyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
)
/*++
{
PCD_IO_CONTEXT IoContext = Context;
- /* ReactOS Change: GCC Unused Variable */
- //PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
-
+ _Analysis_assume_(Context != NULL);
AssertVerifyDeviceIrp( Irp );
-
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
//
// If we got an error (or verify required), remember it in the Irp
//
// Now release the resource
//
- ExReleaseResourceForThreadLite( IoContext->Resource,
- IoContext->ResourceThreadId );
+ _Analysis_assume_lock_held_(*IoContext->Resource);
+ ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId );
//
// and finally, free the context record.
return STATUS_MORE_PROCESSING_REQUIRED;
}
- UNREFERENCED_PARAMETER( DeviceObject );
}
\f
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CdSingleSyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
)
/*++
--*/
{
+ _Analysis_assume_(Context != NULL);
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
AssertVerifyDeviceIrp( Irp );
//
NTSTATUS
NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CdSingleAsyncCompletionRoutine (
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PVOID Context
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
)
/*++
--*/
{
+ PCD_IO_CONTEXT IoContext = Context;
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ _Analysis_assume_(IoContext != NULL);
AssertVerifyDeviceIrp( Irp );
//
if (NT_SUCCESS( Irp->IoStatus.Status )) {
- Irp->IoStatus.Information = ((PCD_IO_CONTEXT) Context)->RequestedByteCount;
+ Irp->IoStatus.Information = IoContext->RequestedByteCount;
}
//
// Now release the resource
//
- ExReleaseResourceForThreadLite( ((PCD_IO_CONTEXT) Context)->Resource,
- ((PCD_IO_CONTEXT) Context)->ResourceThreadId );
+ _Analysis_assume_lock_held_(*IoContext->Resource);
+ ExReleaseResourceForThreadLite( IoContext->Resource, IoContext->ResourceThreadId );
//
// and finally, free the context record.
//
- CdFreeIoContext( Context ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
+ CdFreeIoContext( IoContext );
return STATUS_SUCCESS;
- UNREFERENCED_PARAMETER( DeviceObject );
}
\f
// Local support routine
//
+_When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset == 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + sizeof(RAW_DIRENT))))
+_When_(SafeNodeType(Fcb) != CDFS_NTC_FCB_PATH_TABLE && StartingOffset != 0, _At_(ByteCount, _In_range_(>=, CdAudioDirentSize + SECTOR_SIZE)))
VOID
CdReadAudioSystemFile (
- IN PIRP_CONTEXT IrpContext,
- IN PFCB Fcb,
- IN LONGLONG StartingOffset,
- IN ULONG ByteCount,
- IN PVOID SystemBuffer
+ _In_ PIRP_CONTEXT IrpContext,
+ _In_ PFCB Fcb,
+ _In_ LONGLONG StartingOffset,
+ _In_ _In_range_(>=, CdAudioDirentSize) ULONG ByteCount,
+ _Out_writes_bytes_(ByteCount) PVOID SystemBuffer
)
/*++
// Sanity check that the offset is zero.
//
- ASSERT( StartingOffset == 0 );
+ NT_ASSERT( StartingOffset == 0 );
//
// Store a pseudo path entry in our local buffer.
CdAudioFileNameLength );
//
- // Set the time stamp to be Jan 1, 1995
+ // Set the time stamp to be Jan 1, 1995 00:00
//
RawDirent->RecordTime[0] = 95;
RawDirent->RecordTime[1] = 1;
RawDirent->RecordTime[2] = 1;
- //
- // Now bias by the values in the TOC.
- //
-
- RawDirent->RecordTime[4] = ThisTrack->Address[1] % 60;
- RawDirent->RecordTime[5] = ThisTrack->Address[2] % 60;
-
//
// Put the track number into the file name.
//
return;
}
+
+NTSTATUS
+CdHijackIrpAndFlushDevice (
+ _In_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIRP Irp,
+ _In_ PDEVICE_OBJECT TargetDeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we need to send a flush to a device but
+ we don't have a flush Irp. What this routine does is make a copy
+ of its current Irp stack location, but changes the Irp Major code
+ to a IRP_MJ_FLUSH_BUFFERS amd then send it down, but cut it off at
+ the knees in the completion routine, fix it up and return to the
+ user as if nothing had happened.
+
+Arguments:
+
+ Irp - The Irp to hijack
+
+ TargetDeviceObject - The device to send the request to.
+
+Return Value:
+
+ NTSTATUS - The Status from the flush in case anybody cares.
+
+--*/
+
+{
+ KEVENT Event;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION NextIrpSp;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER( IrpContext );
+
+ //
+ // Get the next stack location, and copy over the stack location
+ //
+
+ NextIrpSp = IoGetNextIrpStackLocation( Irp );
+
+ *NextIrpSp = *IoGetCurrentIrpStackLocation( Irp );
+
+ NextIrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
+ NextIrpSp->MinorFunction = 0;
+
+ //
+ // Set up the completion routine
+ //
+
+ KeInitializeEvent( &Event, NotificationEvent, FALSE );
+
+ IoSetCompletionRoutine( Irp,
+ CdSyncCompletionRoutine,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE );
+
+ //
+ // Send the request.
+ //
+
+ Status = IoCallDriver( TargetDeviceObject, Irp );
+
+ if (Status == STATUS_PENDING) {
+
+ (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
+
+ Status = Irp->IoStatus.Status;
+ }
+
+ //
+ // If the driver doesn't support flushes, return SUCCESS.
+ //
+
+ if (Status == STATUS_INVALID_DEVICE_REQUEST) {
+
+ Status = STATUS_SUCCESS;
+ }
+
+ Irp->IoStatus.Status = 0;
+ Irp->IoStatus.Information = 0;
+
+ return Status;
+}
+
+