📄 deviosup.c
字号:
//
// Now probe the buffer described by the Irp. If we get an exception,
// deallocate the Mdl and return the appropriate "expected" status.
//
try {
MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
Status = STATUS_SUCCESS;
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IoFreeMdl( Mdl );
IrpContext->Irp->MdlAddress = NULL;
if (!FsRtlIsNtstatusExpected( Status )) {
Status = STATUS_INVALID_USER_BUFFER;
}
}
}
//
// Check if we are to raise or return
//
if (Status != STATUS_SUCCESS) {
if (RaiseOnError) {
UdfRaiseStatus( IrpContext, Status );
}
}
//
// Return the status code.
//
return Status;
}
NTSTATUS
UdfPerformDevIoCtrl (
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
)
/*++
Routine Description:
This routine is called to perform DevIoCtrl functions internally within
the filesystem. We take the status from the driver and return it to our
caller.
Arguments:
IoControlCode - Code to send to driver.
Device - This is the device to send the request to.
OutPutBuffer - Pointer to output buffer.
OutputBufferLength - Length of output buffer above.
InternalDeviceIoControl - Indicates if this is an internal or external
Io control code.
OverrideVerify - Indicates if we should tell the driver not to return
STATUS_VERIFY_REQUIRED for mount and verify.
Iosb - If specified, we return the results of the operation here.
Return Value:
NTSTATUS - Status returned by next lower driver.
--*/
{
NTSTATUS Status;
PIRP Irp;
KEVENT Event;
IO_STATUS_BLOCK LocalIosb;
PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
PAGED_CODE();
//
// Check if the user gave us an Iosb.
//
if (ARGUMENT_PRESENT( Iosb )) {
IosbToUse = Iosb;
}
IosbToUse->Status = 0;
IosbToUse->Information = 0;
KeInitializeEvent( &Event, NotificationEvent, FALSE );
Irp = IoBuildDeviceIoControlRequest( IoControlCode,
Device,
NULL,
0,
OutputBuffer,
OutputBufferLength,
InternalDeviceIoControl,
&Event,
IosbToUse );
if (Irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
if (OverrideVerify) {
SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
}
Status = IoCallDriver( Device, Irp );
//
// We check for device not ready by first checking Status
// and then if status pending was returned, the Iosb status
// value.
//
if (Status == STATUS_PENDING) {
(VOID) KeWaitForSingleObject( &Event,
Executive,
KernelMode,
FALSE,
(PLARGE_INTEGER)NULL );
Status = IosbToUse->Status;
}
return Status;
UNREFERENCED_PARAMETER( IrpContext );
}
NTSTATUS
UdfReadSectors (
IN PIRP_CONTEXT IrpContext,
IN LONGLONG StartingOffset,
IN ULONG ByteCount,
IN BOOLEAN ReturnError,
IN OUT PVOID Buffer,
IN PDEVICE_OBJECT TargetDeviceObject
)
/*++
Routine Description:
This routine is called to transfer sectors from the disk to a
specified buffer. It is used for mount and volume verify operations.
This routine is synchronous, it will not return until the operation
is complete or until the operation fails.
The routine allocates an IRP and then passes this IRP to a lower
level driver. Errors may occur in the allocation of this IRP or
in the operation of the lower driver.
Arguments:
StartingOffset - Logical offset on the disk to start the read. This
must be on a sector boundary, no check is made here.
ByteCount - Number of bytes to read. This is an integral number of
sectors, or otherwise a value we know the driver can handle,
no check is made here to confirm this.
ReturnError - Indicates whether we should return TRUE or FALSE
to indicate an error or raise an error condition. This only applies
to the result of the IO. Any other error may cause a raise.
Buffer - Buffer to transfer the disk data into.
TargetDeviceObject - The device object for the volume to be read.
Return Value:
The final status of the operation.
--*/
{
PLONGLONG UseStartingOffset;
LONGLONG LocalStartingOffset;
NTSTATUS Status;
KEVENT Event;
PIRP Irp;
PAGED_CODE();
DebugTrace(( +1, Dbg,
"UdfReadSectors, %x%08x +%x -> %08x from DO %08x\n",
((PLARGE_INTEGER)&StartingOffset)->HighPart,
((PLARGE_INTEGER)&StartingOffset)->LowPart,
ByteCount,
Buffer,
TargetDeviceObject ));
//
// For the time being, we assume that we only read sector-at-a-time.
// This simplifies sparing, and is the only way I am aware of this
// code would not be ready for blocksize != sectorsize. It just is
// not worth writing dead (but straightforward) code right now.
//
ASSERT( IrpContext->Vcb == NULL || ByteCount == SectorSize( IrpContext->Vcb ));
//
// If the volume is spared (and at a point where sparing is possible),
// check if a mapping needs to be performed.
//
if (IrpContext->Vcb &&
IrpContext->Vcb->Pcb &&
IrpContext->Vcb->Pcb->SparingMcb) {
LONGLONG SparingPsn;
if (FsRtlLookupLargeMcbEntry( IrpContext->Vcb->Pcb->SparingMcb,
LlSectorsFromBytes( IrpContext->Vcb, StartingOffset ),
&SparingPsn,
NULL,
NULL,
NULL,
NULL ) &&
SparingPsn != -1) {
StartingOffset = BytesFromSectors( IrpContext->Vcb, (ULONG) SparingPsn );
}
}
//
// Initialize the event.
//
KeInitializeEvent( &Event, NotificationEvent, FALSE );
//
// Correct the starting offset by the method 2 fixup if neccesary. This also
// assumes sector-at-a-time and sector == block so we don't need to fragment
// the request or check if it spans a packet boundary.
//
// We assume that no fixups are required until a Vcb exists. This is true
// since volume recognition may proceed in the first packet.
//
UseStartingOffset = &StartingOffset;
if (IrpContext->Vcb &&
FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP )) {
LocalStartingOffset = UdfMethod2TransformByteOffset( IrpContext->Vcb, StartingOffset );
UseStartingOffset = &LocalStartingOffset;
DebugTrace(( 0, Dbg,
"UdfReadSectors, Method2 Fixup to %x%08x\n",
((PLARGE_INTEGER)UseStartingOffset)->HighPart,
((PLARGE_INTEGER)UseStartingOffset)->LowPart ));
}
//
// Attempt to allocate the IRP. If unsuccessful, raise
// STATUS_INSUFFICIENT_RESOURCES.
//
Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
TargetDeviceObject,
Buffer,
ByteCount,
(PLARGE_INTEGER) UseStartingOffset,
&Event,
&IrpContext->Irp->IoStatus );
if (Irp == NULL) {
UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
}
//
// Ignore the change line (verify) for mount and verify requests
//
SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
//
// Send the request down to the driver. If an error occurs return
// it to the caller.
//
Status = IoCallDriver( TargetDeviceObject, Irp );
//
// If the status was STATUS_PENDING then wait on the event.
//
if (Status == STATUS_PENDING) {
Status = KeWaitForSingleObject( &Event,
Executive,
KernelMode,
FALSE,
NULL );
//
// On a successful wait pull the status out of the IoStatus block.
//
if (NT_SUCCESS( Status )) {
Status = IrpContext->Irp->IoStatus.Status;
}
}
DebugTrace(( -1, Dbg, "UdfReadSectors -> %08x\n", Status ));
//
// Check whether we should raise in the error case.
//
if (!NT_SUCCESS( Status ) && !ReturnError) {
UdfNormalizeAndRaiseStatus( IrpContext, Status );
}
return Status;
}
//
// Local support routine
//
BOOLEAN
UdfPrepareBuffers (
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 PBOOLEAN SparseRuns
)
/*++
Routine Description:
This routine is the worker routine which looks up each run of an IO
request and stores an entry for it in the IoRuns array. If the run
begins on an unaligned disk boundary then we will allocate a buffer
and Mdl for the unaligned portion and put it in the IoRuns entry.
This routine will raise CANT_WAIT if an unaligned transfer is encountered
and this request can't wait.
Arguments:
Irp - Originating Irp for this request.
Fcb - This is the Fcb for this data stream. It may be a file, directory,
path table or the volume file.
UserBuffer - Current position in the user's buffer.
UserBufferOffset - Offset from the start of the original user buffer.
StartingOffset - Offset in the stream to begin the read.
ByteCount - Number of bytes to read. We will fill the IoRuns array up
to this point. We will stop early if we exceed the maximum number
of parallel Ios we support.
IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
this routine is called.
RunCount - Number of entries in the IoRuns array filled here.
ThisByteCount - Number of bytes described by the IoRun entries. Will
not exceed the ByteCount passed in.
SparseRuns - Will indicate whether sparse runs were a component of the
range returned. While not part of the IoRuns, this will affect
our ability to do simple IO.
Return Value:
BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
this is synchronous). FALSE otherwise.
--*/
{
PVCB Vcb;
BOOLEAN Recorded;
BOOLEAN FoundUnaligned = FALSE;
PIO_RUN ThisIoRun = IoRuns;
//
// Following indicate where we are in the current transfer. Current
// position in the file and number of bytes yet to transfer from
// this position.
//
ULONG RemainingByteCount = ByteCount;
LONGLONG CurrentFileOffset = StartingOffset;
//
// Following indicate the state of the user's buffer. We have
// the destination of the next transfer and its offset in the
// buffer. We also have the next available position in the buffer
// available for a scratch buffer. We will align this up to a sector
// boundary.
//
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;
PAGED_CODE();
Vcb = Fcb->Vcb;
//
// Initialize the RunCount, ByteCount and SparseRuns.
//
*RunCount = 0;
*ThisByteCount = 0;
*SparseRuns = FALSE;
//
// Loop while there are more bytes to process or there are
// available entries in the IoRun array.
//
while (TRUE) {
*RunCount += 1;
//
// Initialize the current position in the IoRuns array.
// Find the user's buffer for this portion of the transfer.
//
ThisIoRun->UserBuffer = CurrentUserBuffer;
//
// Find the allocation information for the current offset in the
// stream.
//
Recorded = UdfLookupAllocation( IrpContext,
Fcb,
CurrentFileOffset,
&DiskOffset,
&CurrentByteCount );
//
// Limit ourselves to the data requested.
//
if (CurrentByteCount > RemainingByteCount) {
CurrentByteCount = RemainingByteCount;
}
//
// Handle the case of unrecorded data first.
//
if (!Recorded) {
//
// Note that we did not consume an entry.
//
*RunCount -= 1;
//
// Immediately zero the user buffer and indicate that we found sparse
// runs to the caller.
//
RtlZeroMemory( CurrentUserBuffer, CurrentByteCount );
*SparseRuns = TRUE;
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -