예제 #1
0
NTSTATUS
FatCommonRead (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common read routine for NtReadFile, called from both
    the Fsd, or from the Fsp if a request could not be completed without
    blocking in the Fsd.  This routine has no code where it determines
    whether it is running in the Fsd or Fsp.  Instead, its actions are
    conditionalized by the Wait input parameter, which determines whether
    it is allowed to block or not.  If a blocking condition is encountered
    with Wait == FALSE, however, the request is posted to the Fsp, who
    always calls with WAIT == TRUE.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    PVCB Vcb;
    PFCB FcbOrDcb;
    PCCB Ccb;

    VBO StartingVbo;
    ULONG ByteCount;
    ULONG RequestedByteCount;

    PIO_STACK_LOCATION IrpSp;
    PFILE_OBJECT FileObject;
    TYPE_OF_OPEN TypeOfOpen;

    BOOLEAN PostIrp = FALSE;
    BOOLEAN OplockPostIrp = FALSE;

    BOOLEAN FcbOrDcbAcquired = FALSE;

    BOOLEAN Wait;
    BOOLEAN PagingIo;
    BOOLEAN NonCachedIo;
    BOOLEAN SynchronousIo;

    NTSTATUS Status;

    FAT_IO_CONTEXT StackFatIoContext;

    //
    // A system buffer is only used if we have to access the
    // buffer directly from the Fsp to clear a portion or to
    // do a synchronous I/O, or a cached transfer.  It is
    // possible that our caller may have already mapped a
    // system buffer, in which case we must remember this so
    // we do not unmap it on the way out.
    //

    PVOID SystemBuffer = NULL;

    LARGE_INTEGER StartingByte;

    PAGED_CODE();

    //
    // Get current Irp stack location.
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );
    FileObject = IrpSp->FileObject;

    //
    // Initialize the appropriate local variables.
    //

    Wait          = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
    PagingIo      = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
    NonCachedIo   = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
    SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);

    DebugTrace(+1, Dbg, "CommonRead\n", 0);
    DebugTrace( 0, Dbg, "  Irp                   = %8lx\n", Irp);
    DebugTrace( 0, Dbg, "  ->ByteCount           = %8lx\n", IrpSp->Parameters.Read.Length);
    DebugTrace( 0, Dbg, "  ->ByteOffset.LowPart  = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart);
    DebugTrace( 0, Dbg, "  ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart);

    //
    //  Extract starting Vbo and offset.
    //

    StartingByte = IrpSp->Parameters.Read.ByteOffset;

    StartingVbo = StartingByte.LowPart;

    ByteCount = IrpSp->Parameters.Read.Length;
    RequestedByteCount = ByteCount;

    //
    //  Check for a null request, and return immediately
    //

    if (ByteCount == 0) {

        Irp->IoStatus.Information = 0;
        FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
        return STATUS_SUCCESS;
    }

    //
    // Extract the nature of the read from the file object, and case on it
    //

    TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);

    ASSERT( Vcb != NULL );

    //
    //  Save callers who try to do cached IO to the raw volume from themselves.
    //

    if (TypeOfOpen == UserVolumeOpen) {

        NonCachedIo = TRUE;
    }

    ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));

    //
    // Collect interesting statistics.  The FLAG_USER_IO bit will indicate
    // what type of io we're doing in the FatNonCachedIo function.
    //

    if (PagingIo) {
        CollectReadStats(Vcb, TypeOfOpen, ByteCount);

        if (TypeOfOpen == UserFileOpen) {
            SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        } else {
            ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        }
    }

    ASSERT(!FlagOn( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ));

    //
    //  Allocate if necessary and initialize a FAT_IO_CONTEXT block for
    //  all non cached Io.  For synchronous Io we use stack storage,
    //  otherwise we allocate pool.
    //

    if (NonCachedIo) {

        if (IrpContext->FatIoContext == NULL) {

            if (!Wait) {

                IrpContext->FatIoContext =
                    FsRtlAllocatePoolWithTag( NonPagedPool,
                                              sizeof(FAT_IO_CONTEXT),
                                              TAG_FAT_IO_CONTEXT );

            } else {

                IrpContext->FatIoContext = &StackFatIoContext;

                SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
            }
        }

        RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );

        if (Wait) {

            KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
                               NotificationEvent,
                               FALSE );

        } else {

            IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
                ExGetCurrentResourceThread();

            IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
                ByteCount;

            IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
        }
    }


    //
    // These two cases correspond to either a general opened volume, ie.
    // open ("a:"), or a read of the volume file (boot sector + fat(s))
    //

    if ((TypeOfOpen == VirtualVolumeFile) ||
        (TypeOfOpen == UserVolumeOpen)) {

        LBO StartingLbo;

        StartingLbo = StartingByte.QuadPart;

        DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0);

        if (TypeOfOpen == UserVolumeOpen) {

            //
            //  Verify that the volume for this handle is still valid
            //

            //
            //  Verify that the volume for this handle is still valid, permitting
            //  operations to proceed on dismounted volumes via the handle which
            //  performed the dismount.
            //

            if (!FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT | CCB_FLAG_SENT_FORMAT_UNIT )) {

                FatQuickVerifyVcb( IrpContext, Vcb );
            }

            //
            //  If the caller previously sent a format unit command, then we will allow
            //  their read/write requests to ignore the verify flag on the device, since some
            //  devices send a media change event after format unit, but we don't want to 
            //  process it yet since we're probably in the process of formatting the
            //  media.
            //

            if (FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) {

                SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY );
            }

            if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) {

                (VOID)ExAcquireResourceExclusiveLite( &Vcb->Resource, TRUE );

                try {

                    //
                    //  If the volume isn't locked, flush it.
                    //

                    if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {

                        FatFlushVolume( IrpContext, Vcb, Flush );
                    }

                } finally {

                    ExReleaseResourceLite( &Vcb->Resource );
                }

                SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE );
            }

            if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {

                LBO VolumeSize;

                //
                //  Make sure we don't try to read past end of volume,
                //  reducing the byte count if necessary.
                //

                VolumeSize = (LBO) Vcb->Bpb.BytesPerSector *
                             (Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
                                                      Vcb->Bpb.LargeSectors);

                if (StartingLbo >= VolumeSize) {
                    Irp->IoStatus.Information = 0;
                    FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
                    return STATUS_END_OF_FILE;
                }

                if (ByteCount > VolumeSize - StartingLbo) {

                    ByteCount = RequestedByteCount = (ULONG) (VolumeSize - StartingLbo);

                    //
                    //  For async reads we had set the byte count in the FatIoContext
                    //  above, so fix that here.
                    //

                    if (!Wait) {

                        IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
                            ByteCount;
                    }
                }
            }

            //
            //  For DASD we have to probe and lock the user's buffer
            //

            FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, ByteCount );


        } else {
예제 #2
0
VOID
FatPrePostIrp (
    IN PVOID Context,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs any neccessary work before STATUS_PENDING is
    returned with the Fsd thread.  This routine is called within the
    filesystem and by the oplock package.

Arguments:

    Context - Pointer to the IrpContext to be queued to the Fsp

    Irp - I/O Request Packet.

Return Value:

    None.

--*/

{
    PIO_STACK_LOCATION IrpSp;
    PIRP_CONTEXT IrpContext;

    //
    //  If there is no Irp, we are done.
    //

    if (Irp == NULL) {

        return;
    }

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    IrpContext = (PIRP_CONTEXT) Context;

    //
    //  We need to lock the user's buffer, unless this is an MDL-read,
    //  in which case there is no user buffer.
    //
    //  **** we need a better test than non-MDL (read or write)!

    if (IrpContext->MajorFunction == IRP_MJ_READ
        || IrpContext->MajorFunction == IRP_MJ_WRITE) {

        //
        //  If not an Mdl request, lock the user's buffer.
        //

        if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {

            FatLockUserBuffer( IrpContext,
                               Irp,
                               (IrpContext->MajorFunction == IRP_MJ_READ) ?
                               IoWriteAccess : IoReadAccess,
                               IrpSp->Parameters.Write.Length );
        }

    //
    //  We also need to check whether this is a query file operation.
    //

    } else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
               && IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {

        FatLockUserBuffer( IrpContext,
                           Irp,
                           IoWriteAccess,
                           IrpSp->Parameters.QueryDirectory.Length );

    //
    //  We also need to check whether this is a query ea operation.
    //

    } else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {

        FatLockUserBuffer( IrpContext,
                           Irp,
                           IoWriteAccess,
                           IrpSp->Parameters.QueryEa.Length );

    //
    //  We also need to check whether this is a set ea operation.
    //

    } else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {

        FatLockUserBuffer( IrpContext,
                           Irp,
                           IoReadAccess,
                           IrpSp->Parameters.SetEa.Length );

    //
    //  These two FSCTLs use neither I/O, so check for them.
    //

    } else if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
               (IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
               ((IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
                (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS))) {

        FatLockUserBuffer( IrpContext,
                           Irp,
                           IoWriteAccess,
                           IrpSp->Parameters.FileSystemControl.OutputBufferLength );
    }

    //
    //  Mark that we've already returned pending to the user
    //

    IoMarkIrpPending( Irp );

    return;
}