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

📄 deviosup.c

📁 winddk src目录下的文件系统驱动源码压缩!
💻 C
📖 第 1 页 / 共 5 页
字号:
    IN PULONG RunCount,
    IN PULONG ThisByteCount
    )

/*++

Routine Description:

    This routine is the worker routine which looks up the individual runs
    of an IO request and stores an entry for it in the IoRuns array.  The
    worker routine is for XA files where we need to convert the raw offset
    in the file to logical cooked sectors.  We store one raw sector in
    the Vcb.  If the current read is to that sector then we can simply copy
    whatever bytes are needed from that sector.

Arguments:

    Irp - Originating Irp for this request.

    Fcb - This is the Fcb for this data stream.  It must be a data stream.

    UserBuffer - Current position in the user's buffer.

    UserBufferOffset - Offset of this buffer from the beginning of the user's
        buffer for the original request.

    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.

Return Value:

    None

--*/

{
    PIO_RUN ThisIoRun = IoRuns;
    BOOLEAN PerformedCopy;

    //
    //  The following deal with where we are in the range of raw sectors.
    //  Note that we will bias the input file offset by the RIFF header
    //  to deal directly with the raw sectors.
    //

    ULONG RawSectorOffset;
    ULONG RemainingRawByteCount = ByteCount;
    LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER );

    //
    //  The following is the offset into the cooked sectors for the file.
    //

    LONGLONG CurrentCookedOffset;
    ULONG RemainingCookedByteCount;

    //
    //  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.
    //

    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;
    ULONG CurrentRawByteCount;

    PAGED_CODE();

    //
    //  We need to maintain our position as we walk through the sectors on the disk.
    //  We keep separate values for the cooked offset as well as the raw offset.
    //  These are initialized on sector boundaries and we move through these
    //  the file sector-by-sector.
    //
    //  Try to do 32-bit math.
    //

    if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) {

        //
        //  Prefix/fast: Note that the following are safe since we only
        //               take this path for 32bit offsets.
        //

        CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);

        CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );

        CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);

    //
    //  Otherwise we need to do 64-bit math (sigh).
    //

    } else {

        CurrentRawOffset /= RAW_SECTOR_SIZE;

        CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;

        CurrentRawOffset *= RAW_SECTOR_SIZE;
    }

    //
    //  Now compute the full number of sectors to be read.  Count all of the raw
    //  sectors that need to be read and convert to cooked bytes.
    //

    RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
    CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;

    RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;

    //
    //  Initialize the RunCount and ByteCount.
    //

    *RunCount = 0;
    *ThisByteCount = 0;

    //
    //  Loop while there are more bytes to process or there are
    //  available entries in the IoRun array.
    //

    while (TRUE) {

        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->UserBuffer = CurrentUserBuffer;

        //
        //  Find the allocation information for the current offset in the
        //  stream.
        //

        CdLookupAllocation( IrpContext,
                            Fcb,
                            CurrentCookedOffset,
                            &DiskOffset,
                            &CurrentCookedByteCount );
        //
        //  Maybe we got lucky and this is the same sector as in the
        //  Vcb.
        //

        if (DiskOffset == Fcb->Vcb->XADiskOffset) {

            //
            //  We will perform safe synchronization.  Check again that
            //  this is the correct sector.
            //

            CdLockVcb( IrpContext, Fcb->Vcb );

            if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
                (Fcb->Vcb->XASector != NULL)) {

                //
                //  Copy any bytes we can from the current sector.
                //

                CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;

                //
                //  Check whether we don't go to the end of the sector.
                //

                if (CurrentRawByteCount > RemainingRawByteCount) {

                    CurrentRawByteCount = RemainingRawByteCount;
                }

                RtlCopyMemory( CurrentUserBuffer,
                               Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
                               CurrentRawByteCount );

                CdUnlockVcb( IrpContext, Fcb->Vcb );

                //
                //  Adjust the run count and pointer in the IoRuns array
                //  to show that we didn't use a position.
                //

                *RunCount -= 1;
                ThisIoRun -= 1;

                //
                //  Remember that we performed a copy operation and update
                //  the next available position in the scratch buffer.
                //

                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 {

                //
                //  The safe test showed no available buffer.  Drop down to common code to
                //  perform the Io.
                //

                CdUnlockVcb( IrpContext, Fcb->Vcb );
            }
        }

        //
        //  No work in this pass if we did a copy operation.
        //

        if (!PerformedCopy) {

            //
            //  Limit ourselves by the number of remaining cooked bytes.
            //

            if (CurrentCookedByteCount > RemainingCookedByteCount) {

                CurrentCookedByteCount = RemainingCookedByteCount;
            }

            ThisIoRun->DiskOffset = DiskOffset;
            ThisIoRun->TransferBufferOffset = RawSectorOffset;

            //
            //  We will always need to perform copy operations for XA files.
            //  We allocate an auxillary buffer to read the start of the
            //  transfer.  Then we can use a range of the user's buffer to
            //  perform the next range of the transfer.  Finally we may
            //  need to allocate a buffer for the tail of the transfer.
            //
            //  We can use the user's buffer (at the current scratch buffer) if the
            //  following are true:
            //
            //      If we are to store the beginning of the raw sector in the user's buffer.
            //      The current scratch buffer precedes the destination in the user's buffer 
            //          (and hence also lies within it)
            //      There are enough bytes remaining in the buffer for at least one
            //          raw sector.
            //

            if ((RawSectorOffset == 0) &&
                (ScratchUserBufferOffset <= CurrentUserBufferOffset) &&
                (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount >= RAW_SECTOR_SIZE)) {

                //
                //  We can use the scratch buffer.  We must ensure we don't send down reads
                //  greater than the device can handle, since the driver is unable to split
                //  raw requests.
                //

                if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {

                    CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
    
                } else {

                    CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
                    CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
                }

                //
                //  Now make sure we are within the page transfer limit.
                //

                while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer, RawSectorAlign( CurrentRawByteCount)) > 
                       Fcb->Vcb->MaximumPhysicalPages )  {

                    CurrentRawByteCount -= RAW_SECTOR_SIZE;
                    CurrentCookedByteCount -= SECTOR_SIZE;
                }

                //
                //  Trim the number of bytes to read if it won't fit into the current buffer. Take
                //  account of the fact that we must read in whole raw sector multiples.
                //

                while ( RawSectorAlign( CurrentRawByteCount) > 
                        (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount) )  {

                    CurrentRawByteCount -= RAW_SECTOR_SIZE;
                    CurrentCookedByteCount -= SECTOR_SIZE;
                }

                //
                //  Now trim the maximum number of raw bytes to the remaining bytes.
                //

                if (CurrentRawByteCount > RemainingRawByteCount) {

                    CurrentRawByteCount = RemainingRawByteCount;
                }
                
                //
                //  Update the IO run array.  We point to the scratch buffer as
                //  well as the buffer and Mdl in the original Irp.
                //

                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->TransferMdl = Irp->MdlAddress;
                ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer, 
                                                             ScratchUserBufferOffset,
                                                             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 {

                //
                //  We need to determine the number of bytes to transfer and the
                //  offset into this page to begin the transfer.
                //
                //  We will transfer only one raw sector.
                //

                ThisIoRun->DiskByteCount = SECTOR_SIZE;

                CurrentCookedByteCount = SECTOR_SIZE;

                ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
                ThisIoRun->TransferBufferOffset = RawSectorOffset;

                if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {

                    ThisIoRun->TransferByteCount = RemainingRawByteCount;
                }

                CurrentRawByteCount = ThisIoRun->TransferByteCount;

                //
                //  We need to allocate an auxillary buffer.  We will allocate
                //  a single page.  Then we will build an Mdl to describe the buffer.
                //

                ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );

                //
                //  Allocate and build the Mdl to describe this buffer.
                //

                ThisIoRun->T

⌨️ 快捷键说明

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