示例#1
0
文件: cddata.c 项目: 340211173/Driver
NTSTATUS
CdFsdDispatch (
    _In_ PDEVICE_OBJECT DeviceObject,
    _Inout_ PIRP Irp
    )

/*++

Routine Description:

    This is the driver entry to all of the Fsd dispatch points.

    Conceptually the Io routine will call this routine on all requests
    to the file system.  We case on the type of request and invoke the
    correct handler for this type of request.  There is an exception filter
    to catch any exceptions in the CDFS code as well as the CDFS process
    exception routine.

    This routine allocates and initializes the IrpContext for this request as
    well as updating the top-level thread context as necessary.  We may loop
    in this routine if we need to retry the request for any reason.  The
    status code STATUS_CANT_WAIT is used to indicate this.  Suppose the disk
    in the drive has changed.  An Fsd request will proceed normally until it
    recognizes this condition.  STATUS_VERIFY_REQUIRED is raised at that point
    and the exception code will handle the verify and either return
    STATUS_CANT_WAIT or STATUS_PENDING depending on whether the request was
    posted.

Arguments:

    DeviceObject - Supplies the volume device object for this request

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The FSD status for the IRP

--*/

{
    THREAD_CONTEXT ThreadContext = {0};
    PIRP_CONTEXT IrpContext = NULL;
    BOOLEAN Wait;

#ifdef CD_SANITY
    PVOID PreviousTopLevel;
#endif

    NTSTATUS Status;

#if DBG

    KIRQL SaveIrql = KeGetCurrentIrql();

#endif

    ASSERT_OPTIONAL_IRP( Irp );

    UNREFERENCED_PARAMETER( DeviceObject );

    FsRtlEnterFileSystem();

#ifdef CD_SANITY
    PreviousTopLevel = IoGetTopLevelIrp();
#endif

    //
    //  Loop until this request has been completed or posted.
    //

    do {

        //
        //  Use a try-except to handle the exception cases.
        //

        try {

            //
            //  If the IrpContext is NULL then this is the first pass through
            //  this loop.
            //

            if (IrpContext == NULL) {

                //
                //  Decide if this request is waitable an allocate the IrpContext.
                //  If the file object in the stack location is NULL then this
                //  is a mount which is always waitable.  Otherwise we look at
                //  the file object flags.
                //

                if (IoGetCurrentIrpStackLocation( Irp )->FileObject == NULL) {

                    Wait = TRUE;

                } else {

                    Wait = CanFsdWait( Irp );
                }

                IrpContext = CdCreateIrpContext( Irp, Wait );

                //
                //  Update the thread context information.
                //

                CdSetThreadContext( IrpContext, &ThreadContext );

#ifdef CD_SANITY
                NT_ASSERT( !CdTestTopLevel ||
                        SafeNodeType( IrpContext->TopLevel ) == CDFS_NTC_IRP_CONTEXT );
#endif

            //
            //  Otherwise cleanup the IrpContext for the retry.
            //

            } else {

                //
                //  Set the MORE_PROCESSING flag to make sure the IrpContext
                //  isn't inadvertently deleted here.  Then cleanup the
                //  IrpContext to perform the retry.
                //

                SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
                CdCleanupIrpContext( IrpContext, FALSE );
            }

            //
            //  Case on the major irp code.
            //

            switch (IrpContext->MajorFunction) {

            case IRP_MJ_CREATE :

                Status = CdCommonCreate( IrpContext, Irp );
                break;

            case IRP_MJ_CLOSE :

                Status = CdCommonClose( IrpContext, Irp );
                break;

            case IRP_MJ_READ :

                //
                //  If this is an Mdl complete request, don't go through
                //  common read.
                //

                if (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE )) {

                    Status = CdCompleteMdl( IrpContext, Irp );

                } else {

                    Status = CdCommonRead( IrpContext, Irp );
                }

                break;

            case IRP_MJ_WRITE :

                Status = CdCommonWrite( IrpContext, Irp );
                break;

            case IRP_MJ_QUERY_INFORMATION :

                Status = CdCommonQueryInfo( IrpContext, Irp );
                break;

            case IRP_MJ_SET_INFORMATION :

                Status = CdCommonSetInfo( IrpContext, Irp );
                break;

            case IRP_MJ_QUERY_VOLUME_INFORMATION :

                Status = CdCommonQueryVolInfo( IrpContext, Irp );
                break;

            case IRP_MJ_DIRECTORY_CONTROL :

                Status = CdCommonDirControl( IrpContext, Irp );
                break;

            case IRP_MJ_FILE_SYSTEM_CONTROL :

                Status = CdCommonFsControl( IrpContext, Irp );
                break;

            case IRP_MJ_DEVICE_CONTROL :

                Status = CdCommonDevControl( IrpContext, Irp );
                break;

            case IRP_MJ_LOCK_CONTROL :

                Status = CdCommonLockControl( IrpContext, Irp );
                break;

            case IRP_MJ_CLEANUP :

                Status = CdCommonCleanup( IrpContext, Irp );
                break;

            case IRP_MJ_PNP :

                Status = CdCommonPnp( IrpContext, Irp );
                break;

            case IRP_MJ_SHUTDOWN :
            
                Status = CdCommonShutdown( IrpContext, Irp );
                break;

            default :

                Status = STATUS_INVALID_DEVICE_REQUEST;
                CdCompleteRequest( IrpContext, Irp, Status );
            }

        } except( CdExceptionFilter( IrpContext, GetExceptionInformation() )) {

            Status = CdProcessException( IrpContext, Irp, GetExceptionCode() );
        }

    } while (Status == STATUS_CANT_WAIT);

#ifdef CD_SANITY
    NT_ASSERT( !CdTestTopLevel ||
            (PreviousTopLevel == IoGetTopLevelIrp()) );
#endif

    FsRtlExitFileSystem();

    NT_ASSERT( SaveIrql == KeGetCurrentIrql( ));

    return Status;
}
示例#2
0
VOID
CdFindPrefix (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFCB *CurrentFcb,
    _Inout_ PUNICODE_STRING RemainingName,
    _In_ BOOLEAN IgnoreCase
    )

/*++

Routine Description:

    This routine begins from the given CurrentFcb and walks through all of
    components of the name looking for the longest match in the prefix
    splay trees.  The search is relative to the starting Fcb so the
    full name may not begin with a '\'.  On return this routine will
    update Current Fcb with the lowest point it has travelled in the
    tree.  It will also hold only that resource on return and it must
    hold that resource.

Arguments:

    CurrentFcb - Address to store the lowest Fcb we find on this search.
        On return we will have acquired this Fcb.  On entry this is the
        Fcb to examine.

    RemainingName - Supplies a buffer to store the exact case of the name being
        searched for.  Initially will contain the upcase name based on the
        IgnoreCase flag.

    IgnoreCase - Indicates if we are doing a case-insensitive compare.

Return Value:

    None

--*/

{
    UNICODE_STRING LocalRemainingName;

    UNICODE_STRING FinalName;

    PNAME_LINK NameLink;
    PPREFIX_ENTRY PrefixEntry;

    PAGED_CODE();

    //
    //  Make a local copy of the input strings.
    //

    LocalRemainingName = *RemainingName;

    //
    //  Loop until we find the longest matching prefix.
    //

    while (TRUE) {

        //
        //  If there are no characters left or we are not at an IndexFcb then
        //  return immediately.
        //

        if ((LocalRemainingName.Length == 0) ||
            (SafeNodeType( *CurrentFcb ) != CDFS_NTC_FCB_INDEX)) {

            return;
        }

        //
        //  Split off the next component from the name.
        //

        CdDissectName( IrpContext,
                       &LocalRemainingName,
                       &FinalName );

        //
        //  Check if this name is in the splay tree for this Scb.
        //

        if (IgnoreCase) {

            NameLink = CdFindNameLink( IrpContext,
                                       &(*CurrentFcb)->IgnoreCaseRoot,
                                       &FinalName );

            //
            //  Get the prefix entry from this NameLink.  Don't access any
            //  fields within it until we verify we have a name link.
            //

            PrefixEntry = (PPREFIX_ENTRY) CONTAINING_RECORD( NameLink,
                                                             PREFIX_ENTRY,
                                                             IgnoreCaseName );

        } else {

            NameLink = CdFindNameLink( IrpContext,
                                       &(*CurrentFcb)->ExactCaseRoot,
                                       &FinalName );

            PrefixEntry = (PPREFIX_ENTRY) CONTAINING_RECORD( NameLink,
                                                             PREFIX_ENTRY,
                                                             ExactCaseName );
        }

        //
        //  If we didn't find a match then exit.
        //

        if (NameLink == NULL) { return; }

        //
        //  If this is a case-insensitive match then copy the exact case of the name into
        //  the input buffer.
        //

        if (IgnoreCase) {

            RtlCopyMemory( FinalName.Buffer,
                           PrefixEntry->ExactCaseName.FileName.Buffer,
                           PrefixEntry->ExactCaseName.FileName.Length );
        }

        //
        //  Update the caller's remaining name string to reflect the fact that we found
        //  a match.
        //

        *RemainingName = LocalRemainingName;

        //
        //  Move down to the next component in the tree.  Acquire without waiting.
        //  If this fails then lock the Fcb to reference this Fcb and then drop
        //  the parent and acquire the child.
        //

        if (!CdAcquireFcbExclusive( IrpContext, PrefixEntry->Fcb, TRUE )) {

            //
            //  If we can't wait then raise CANT_WAIT.
            //

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

                CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
            }

            CdLockVcb( IrpContext, IrpContext->Vcb );
            PrefixEntry->Fcb->FcbReference += 1;
            CdUnlockVcb( IrpContext, IrpContext->Vcb );

            CdReleaseFcb( IrpContext, *CurrentFcb );
            CdAcquireFcbExclusive( IrpContext, PrefixEntry->Fcb, FALSE );

            CdLockVcb( IrpContext, IrpContext->Vcb );
            PrefixEntry->Fcb->FcbReference -= 1;
            CdUnlockVcb( IrpContext, IrpContext->Vcb );

        } else {

            CdReleaseFcb( IrpContext, *CurrentFcb );
        }

        *CurrentFcb = PrefixEntry->Fcb;
    }
}
示例#3
0
文件: close.c 项目: kcrazy/winekit
VOID
CdFspClose (
    IN PVCB Vcb OPTIONAL
    )

/*++

Routine Description:

    This routine is called to process the close queues in the CdData.  If the
    Vcb is passed then we want to remove all of the closes for this Vcb.
    Otherwise we will do as many of the delayed closes as we need to do.

Arguments:

    Vcb - If specified then we are looking for all of the closes for the
        given Vcb.

Return Value:

    None

--*/

{
    PIRP_CONTEXT IrpContext;
    IRP_CONTEXT StackIrpContext;

    THREAD_CONTEXT ThreadContext;

    PFCB Fcb;
    ULONG UserReference;

    ULONG VcbHoldCount = 0;
    PVCB CurrentVcb = NULL;

    BOOLEAN PotentialVcbTeardown = FALSE;

    PAGED_CODE();

    FsRtlEnterFileSystem();

    //
    //  Continue processing until there are no more closes to process.
    //

    while (IrpContext = CdRemoveClose( Vcb )) {

        //
        //  If we don't have an IrpContext then use the one on the stack.
        //  Initialize it for this request.
        //

        if (SafeNodeType( IrpContext ) != CDFS_NTC_IRP_CONTEXT ) {

            //
            //  Update the local values from the IrpContextLite.
            //

            Fcb = ((PIRP_CONTEXT_LITE) IrpContext)->Fcb;
            UserReference = ((PIRP_CONTEXT_LITE) IrpContext)->UserReference;

            //
            //  Update the stack irp context with the values from the
            //  IrpContextLite.
            //

            CdInitializeStackIrpContext( &StackIrpContext,
                                         (PIRP_CONTEXT_LITE) IrpContext );

            //
            //  Free the IrpContextLite.
            //

            CdFreeIrpContextLite( (PIRP_CONTEXT_LITE) IrpContext );

            //
            //  Remember we have the IrpContext from the stack.
            //

            IrpContext = &StackIrpContext;

        //
        //  Otherwise cleanup the existing IrpContext.
        //

        } else {

            //
            //  Remember the Fcb and user reference count.
            //

            Fcb = (PFCB) IrpContext->Irp;
            IrpContext->Irp = NULL;

            UserReference = (ULONG) IrpContext->ExceptionStatus;
            IrpContext->ExceptionStatus = STATUS_SUCCESS;
        }

        //
        //  We have an IrpContext.  Now we need to set the top level thread
        //  context.
        //

        SetFlag( IrpContext->Flags, IRP_CONTEXT_FSP_FLAGS );

        //
        //  If we were given a Vcb then there is a request on top of this.
        //

        if (ARGUMENT_PRESENT( Vcb )) {

            ClearFlag( IrpContext->Flags,
                       IRP_CONTEXT_FLAG_TOP_LEVEL | IRP_CONTEXT_FLAG_TOP_LEVEL_CDFS );
        }

        CdSetThreadContext( IrpContext, &ThreadContext );

        //
        //  If we have hit the maximum number of requests to process without
        //  releasing the Vcb then release the Vcb now.  If we are holding
        //  a different Vcb to this one then release the previous Vcb.
        //
        //  In either case acquire the current Vcb.
        //
        //  We use the MinDelayedCloseCount from the CdData since it is
        //  a convenient value based on the system size.  Only thing we are trying
        //  to do here is prevent this routine starving other threads which
        //  may need this Vcb exclusively.
        //
        //  Note that the check for potential teardown below is unsafe.  We'll 
        //  repeat later within the cddata lock.
        //

        PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) &&
                               (Fcb->Vcb->VcbCondition != VcbMounted) &&
                               (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
                               (Fcb->Vcb->VcbCleanup == 0);

        if (PotentialVcbTeardown ||
            (VcbHoldCount > CdData.MinDelayedCloseCount) ||
            (Fcb->Vcb != CurrentVcb)) {

            if (CurrentVcb != NULL) {

                CdReleaseVcb( IrpContext, CurrentVcb );
            }

            if (PotentialVcbTeardown) {

                CdAcquireCdData( IrpContext );

                //
                //  Repeat the checks with global lock held.  The volume could have
                //  been remounted while we didn't hold the lock.
                //

                PotentialVcbTeardown = !ARGUMENT_PRESENT( Vcb ) &&
                                       (Fcb->Vcb->VcbCondition != VcbMounted) &&
                                       (Fcb->Vcb->VcbCondition != VcbMountInProgress) &&
                                       (Fcb->Vcb->VcbCleanup == 0);
                                
                if (!PotentialVcbTeardown)  {

                    CdReleaseCdData( IrpContext);
                }
            }

            CurrentVcb = Fcb->Vcb;
            CdAcquireVcbShared( IrpContext, CurrentVcb, FALSE );

            VcbHoldCount = 0;

        } else {

            VcbHoldCount += 1;
        }

        //
        //  Call our worker routine to perform the close operation.
        //

        CdCommonClosePrivate( IrpContext, CurrentVcb, Fcb, UserReference, FALSE );

        //
        //  If the reference count on this Vcb is below our residual reference
        //  then check if we should dismount the volume.
        //

        if (PotentialVcbTeardown) {

            CdReleaseVcb( IrpContext, CurrentVcb );
            CdCheckForDismount( IrpContext, CurrentVcb, FALSE );

            CurrentVcb = NULL;

            CdReleaseCdData( IrpContext );
            PotentialVcbTeardown = FALSE;
        }

        //
        //  Complete the current request to cleanup the IrpContext.
        //

        CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
    }

    //
    //  Release any Vcb we may still hold.
    //

    if (CurrentVcb != NULL) {

        CdReleaseVcb( IrpContext, CurrentVcb );

    }

    FsRtlExitFileSystem();
}
示例#4
0
VOID
NtfsReleaseSharedResources (
    IN PIRP_CONTEXT IrpContext
    )

/*++

Routine Description:

    The routine releases all of the resources acquired shared for
    transaction.  The SharedScb structure is freed if necessary and
    the Irp Context field is cleared.

Arguments:


Return Value:

    None.

--*/
{

    PAGED_CODE();

    //
    //  If only one then free the Scb main resource.
    //

    if (IrpContext->SharedScbSize == 1) {

#ifdef _CAIRO_
        if (SafeNodeType(IrpContext->SharedScb) == NTFS_NTC_QUOTA_CONTROL) {
            NtfsReleaseQuotaControl( IrpContext,
                              (PQUOTA_CONTROL_BLOCK) IrpContext->SharedScb );
        } else {
            ExReleaseResource( ((PSCB) IrpContext->SharedScb)->Header.Resource );
        }

#else
        ExReleaseResource( ((PSCB) IrpContext->SharedScb)->Header.Resource );
#endif // _CAIRO_

    //
    //  Otherwise traverse the array and look for Scb's to release.
    //

    } else {

        PSCB *NextScb;
        ULONG Count;

        NextScb = IrpContext->SharedScb;
        Count = IrpContext->SharedScbSize;

        do {

            if (*NextScb != NULL) {

#ifdef _CAIRO_
                if (SafeNodeType(*NextScb) == NTFS_NTC_QUOTA_CONTROL) {

                    NtfsReleaseQuotaControl( IrpContext,
                                      (PQUOTA_CONTROL_BLOCK) *NextScb );
                } else {

                    ExReleaseResource( (*NextScb)->Header.Resource );
                }

#else
                ExReleaseResource( (*NextScb)->Header.Resource );
#endif // _CAIRO_

            }

            Count -= 1;
            NextScb += 1;

        } while (Count != 0);

        NtfsFreePool( IrpContext->SharedScb );
    }

    IrpContext->SharedScb = NULL;
    IrpContext->SharedScbSize = 0;

}