⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deviosup.c

📁 windows 2000中的UDF文件系统的驱动程序.只有读的功能,不支持未关闭的盘片.只支持UDF2.0以下版本,不支持VAT格式的UDF.
💻 C
📖 第 1 页 / 共 4 页
字号:
/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    DevIoSup.c

Abstract:

    This module implements the low lever disk read/write support for Udfs.

Author:

    Dan Lovinger    [DanLo]   11-Jun-1996

Revision History:

--*/

#include "UdfProcs.h"

//
//  The Bug check file id for this module
//

#define BugCheckFileId                   (UDFS_BUG_CHECK_DEVIOSUP)

//
//  The local debug trace level
//

#define Dbg                              (UDFS_DEBUG_LEVEL_DEVIOSUP)

//
//  Local structure definitions
//

//
//  An array of these structures is passed to UdfMultipleAsync describing
//  a set of runs to execute in parallel.
//

typedef struct _IO_RUN {

    //
    //  Disk offset to read from and number of bytes to read.  These
    //  must be a multiple of a sector and the disk offset is also a
    //  multiple of sector.
    //

    LONGLONG DiskOffset;
    ULONG DiskByteCount;

    //
    //  Current position in user buffer.  This is the final destination for
    //  this portion of the Io transfer.
    //

    PVOID UserBuffer;

    //
    //  Buffer to perform the transfer to.  If this is the same as the
    //  user buffer above then we are using the user's buffer.  Otherwise
    //  we either allocated a temporary buffer or are using a different portion
    //  of the user's buffer.
    //
    //  TransferBuffer - Read full sectors into this location.  This can
    //      be a pointer into the user's buffer at the exact location the
    //      data should go.  It can also be an earlier point in the user's
    //      buffer if the complete I/O doesn't start on a sector boundary.
    //      It may also be a pointer into an allocated buffer.
    //
    //  TransferByteCount - Count of bytes to transfer to user's buffer.  A
    //      value of zero indicates that we did do the transfer into the
    //      user's buffer directly.
    //
    //  TransferBufferOffset - Offset in this buffer to begin the transfer
    //      to the user's buffer.
    //

    PVOID TransferBuffer;
    ULONG TransferByteCount;
    ULONG TransferBufferOffset;

    //
    //  This is the Mdl describing the locked pages in memory.  It may
    //  be allocated to describe the allocated buffer.  Or it may be
    //  the Mdl in the originating Irp.  The MdlOffset is the offset of
    //  the current buffer from the beginning of the buffer described by
    //  the Mdl below.  If the TransferMdl is not the same as the Mdl
    //  in the user's Irp then we know we have allocated it.
    //

    PMDL TransferMdl;
    PVOID TransferVirtualAddress;

    //
    //  Associated Irp used to perform the Io.
    //

    PIRP SavedIrp;

} IO_RUN;
typedef IO_RUN *PIO_RUN;

#define MAX_PARALLEL_IOS            5

//
//  Local support routines
//

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,
    OUT PBOOLEAN SparseRuns
    );

BOOLEAN
UdfFinishBuffers (
    IN PIRP_CONTEXT IrpContext,
    IN PIO_RUN IoRuns,
    IN ULONG RunCount,
    IN BOOLEAN FinalCleanup
    );

VOID
UdfMultipleAsync (
    IN PIRP_CONTEXT IrpContext,
    IN ULONG RunCount,
    IN PIO_RUN IoRuns
    );

VOID
UdfSingleAsync (
    IN PIRP_CONTEXT IrpContext,
    IN LONGLONG ByteOffset,
    IN ULONG ByteCount
    );

VOID
UdfWaitSync (
    IN PIRP_CONTEXT IrpContext
    );

NTSTATUS
UdfMultiSyncCompletionRoutine (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    );

NTSTATUS
UdfMultiAsyncCompletionRoutine (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    );

NTSTATUS
UdfSingleSyncCompletionRoutine (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    );

NTSTATUS
UdfSingleAsyncCompletionRoutine (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    );

#ifdef ALLOC_PRAGMA
#endif

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, UdfCreateUserMdl)
#pragma alloc_text(PAGE, UdfMultipleAsync)
#pragma alloc_text(PAGE, UdfNonCachedRead)
#pragma alloc_text(PAGE, UdfFinishBuffers)
#pragma alloc_text(PAGE, UdfPrepareBuffers)
#pragma alloc_text(PAGE, UdfSingleAsync)
#pragma alloc_text(PAGE, UdfWaitSync)
#pragma alloc_text(PAGE, UdfPerformDevIoCtrl)
#pragma alloc_text(PAGE, UdfReadSectors)
#endif



NTSTATUS
UdfNonCachedRead (
    IN PIRP_CONTEXT IrpContext,
    IN PFCB Fcb,
    IN LONGLONG StartingOffset,
    IN ULONG ByteCount
    )

/*++

Routine Description:

    This routine performs the non-cached reads of sectors.  This is done by
    performing the following in a loop.

        Fill in the IoRuns array for the next block of Io.
        Send the Io to the device.
        Perform any cleanup on the Io runs array.

    We will not do async Io to any request that generates non-aligned Io.
    Also we will not perform async Io if it will exceed the size of our
    IoRuns array.  These should be the unusual cases but we will raise
    or return CANT_WAIT in this routine if we detect this case.

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 = STATUS_SUCCESS;

    IO_RUN IoRuns[MAX_PARALLEL_IOS];
    ULONG RunCount = 0;
    ULONG CleanupRunCount = 0;

    PVOID UserBuffer;
    ULONG UserBufferOffset = 0;
    LONGLONG CurrentOffset = StartingOffset;
    ULONG RemainingByteCount = ByteCount;
    ULONG ThisByteCount;

    BOOLEAN Unaligned;
    BOOLEAN SparseRuns;
    BOOLEAN FlushIoBuffers = FALSE;
    BOOLEAN FirstPass = TRUE;

    PAGED_CODE();

    //
    //  We want to make sure the user's buffer is locked in all cases.
    //

    if (IrpContext->Irp->MdlAddress == NULL) {

        UdfCreateUserMdl( IrpContext, ByteCount, TRUE );
    }

    //
    //  Use a try-finally to perform the final cleanup.
    //

    try {

        UdfMapUserBuffer( IrpContext, &UserBuffer);

        //
        //  Loop while there are more bytes to transfer.
        //

        do {

            //
            //  Call prepare buffers to set up the next entries
            //  in the IoRuns array.  Remember if there are any
            //  unaligned entries.
            //

            RtlZeroMemory( IoRuns, sizeof( IoRuns ));

            Unaligned = UdfPrepareBuffers( IrpContext,
                                           IrpContext->Irp,
                                           Fcb,
                                           UserBuffer,
                                           UserBufferOffset,
                                           CurrentOffset,
                                           RemainingByteCount,
                                           IoRuns,
                                           &CleanupRunCount,
                                           &ThisByteCount,
                                           &SparseRuns );


            RunCount = CleanupRunCount;

            //
            //  Quickly finish if we wound up having no IO to perform.  This will
            //  occur in the presence of unrecorded sectors.
            //

            ASSERT( !(SparseRuns && FlagOn( Fcb->FcbState, FCB_STATE_VMCB_MAPPING|FCB_STATE_EMBEDDED_DATA )));

            if (RunCount == 0) {

                try_leave( Status = IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS );
            }

            //
            //  If this is an async request and there aren't enough entries
            //  in the Io array then post the request.  This routine will
            //  always raise if we are doing any unaligned Io for an
            //  async request.
            //

            if ((ThisByteCount < RemainingByteCount) &&
                !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {

                UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
            }

            //
            //  If the entire Io is contained in a single run then
            //  we can pass the Io down to the driver.  Send the driver down
            //  and wait on the result if this is synchronous.  We cannot
            //  do this simple form (just chucking the IRP down) if some
            //  sparse runs were encountered.
            //

            if ((RunCount == 1) && !Unaligned && !SparseRuns && FirstPass) {

                UdfSingleAsync( IrpContext,
                                IoRuns[0].DiskOffset,
                                IoRuns[0].DiskByteCount );

                //
                //  No cleanup needed for the IoRuns array here.
                //

                CleanupRunCount = 0;

                //
                //  Wait if we are synchronous, otherwise return
                //

                if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {

                    UdfWaitSync( 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;
                }

                try_leave( NOTHING );
            }

            //
            //  Otherwise we will perform multiple Io to read in the data.
            //
            
            UdfMultipleAsync( IrpContext, RunCount, IoRuns );

            //
            //  No cleanup needed on the IoRuns now.
            //

            CleanupRunCount = 0;

            //
            //  If this is a synchronous request then perform any necessary
            //  post-processing.
            //

            if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {

                //
                //  Wait for the request to complete.
                //

                UdfWaitSync( IrpContext );

                Status = IrpContext->Irp->IoStatus.Status;

                //
                //  Exit this loop if there is an error.
                //

                if (!NT_SUCCESS( Status )) {

                    try_leave( NOTHING );
                }

                //
                //  Perform post read operations on the IoRuns if
                //  necessary.
                //

                if (Unaligned &&
                    UdfFinishBuffers( IrpContext, IoRuns, RunCount, FALSE )) {

                    FlushIoBuffers = TRUE;
                }

                //
                //  Exit this loop if there are no more bytes to transfer
                //  or we have any error.
                //

                RemainingByteCount -= ThisByteCount;
                CurrentOffset += ThisByteCount;
                UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
                UserBufferOffset += ThisByteCount;

            //
            //  Otherwise this is an asynchronous request.  Always return
            //  STATUS_PENDING.
            //

            } else {

                ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
                CleanupRunCount = 0;
                try_leave( Status = STATUS_PENDING );
                break;
            }

            FirstPass = FALSE;
        } while (RemainingByteCount != 0);

        //
        //  Flush the hardware cache if we performed any copy operations.
        //

        if (FlushIoBuffers) {

            KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
        }

    } finally {

        DebugUnwind( "UdfNonCachedRead" );

        //
        //  Perform final cleanup on the IoRuns if necessary.
        //

        if (CleanupRunCount != 0) {

            UdfFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE );
        }
    }

    return Status;
}


NTSTATUS
UdfCreateUserMdl (
    IN PIRP_CONTEXT IrpContext,
    IN ULONG BufferLength,
    IN BOOLEAN RaiseOnError
    )

/*++

Routine Description:

    This routine locks the specified buffer for read access (we only write into
    the buffer).  The file system requires this routine since it does not
    ask the I/O system to lock its buffers for direct I/O.  This routine
    may only be called from the Fsd while still in the user context.

    This routine is only called if there is not already an Mdl.

Arguments:

    BufferLength - Length of user buffer.

    RaiseOnError - Indicates if our caller wants this routine to raise on
        an error condition.

Return Value:

    NTSTATUS - Status from this routine.  Error status only returned if
        RaiseOnError is FALSE.

--*/

{
    NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
    PMDL Mdl;

    PAGED_CODE();

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_IRP( IrpContext->Irp );
    ASSERT( IrpContext->Irp->MdlAddress == NULL );

    //
    // Allocate the Mdl, and Raise if we fail.
    //

    Mdl = IoAllocateMdl( IrpContext->Irp->UserBuffer,
                         BufferLength,
                         FALSE,
                         FALSE,
                         IrpContext->Irp );

    if (Mdl != NULL) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -