示例#1
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
IopMountVolume(IN PDEVICE_OBJECT DeviceObject,
               IN BOOLEAN AllowRawMount,
               IN BOOLEAN DeviceIsLocked,
               IN BOOLEAN Alertable,
               OUT PVPB *Vpb)
{
    KEVENT Event;
    NTSTATUS Status;
    IO_STATUS_BLOCK IoStatusBlock;
    PIRP Irp;
    PIO_STACK_LOCATION StackPtr;
    PLIST_ENTRY FsList, ListEntry;
    LIST_ENTRY LocalList;
    PDEVICE_OBJECT AttachedDeviceObject = DeviceObject;
    PDEVICE_OBJECT FileSystemDeviceObject, ParentFsDeviceObject;
    ULONG FsStackOverhead, RegistrationOps;
    PAGED_CODE();

    /* Check if the device isn't already locked */
    if (!DeviceIsLocked)
    {
        /* Lock it ourselves */
        Status = KeWaitForSingleObject(&DeviceObject->DeviceLock,
                                       Executive,
                                       KeGetPreviousMode(),
                                       Alertable,
                                       NULL);
        if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC))
        {
            /* Don't mount if we were interrupted */
            return Status;
        }
    }

    /* Acquire the FS Lock*/
    KeEnterCriticalRegion();
    ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE);

    /* Make sure we weren't already mounted */
    if (!(DeviceObject->Vpb->Flags & (VPB_MOUNTED | VPB_REMOVE_PENDING)))
    {
        /* Initialize the event to wait on */
        KeInitializeEvent(&Event, NotificationEvent, FALSE);

        /* Remove the verify flag and get the actual device to mount */
        DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
        while (AttachedDeviceObject->AttachedDevice)
        {
            /* Get the next one */
            AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
        }

        /* Reference it */
        ObReferenceObject(AttachedDeviceObject);

        /* For a mount operation, this can only be a Disk, CD-ROM or tape */
        if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) ||
            (DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK))
        {
            /* Use the disk list */
            FsList = &IopDiskFileSystemQueueHead;
        }
        else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM)
        {
            /* Use the CD-ROM list */
            FsList = &IopCdRomFileSystemQueueHead;
        }
        else
        {
            /* It's gotta be a tape... */
            FsList = &IopTapeFileSystemQueueHead;
        }

        /* Now loop the fs list until one of the file systems accepts us */
        Status = STATUS_UNSUCCESSFUL;
        ListEntry = FsList->Flink;
        while ((ListEntry != FsList) && !(NT_SUCCESS(Status)))
        {
            /*
             * If we're not allowed to mount this volume and this is our last
             * (but not only) chance to mount it...
             */
            if (!(AllowRawMount) &&
                (ListEntry->Flink == FsList) &&
                (ListEntry != FsList->Flink))
            {
                /* Then fail this mount request */
                break;
            }

            /*
             * Also check if this is a raw mount and there are other file
             * systems on the list.
             */
            if ((DeviceObject->Vpb->Flags & VPB_RAW_MOUNT) &&
                (ListEntry->Flink != FsList))
            {
                /* Then skip this entry */
                continue;
            }

            /* Get the Device Object for this FS */
            FileSystemDeviceObject = CONTAINING_RECORD(ListEntry,
                                                       DEVICE_OBJECT,
                                                       Queue.ListEntry);
            ParentFsDeviceObject = FileSystemDeviceObject;

            /*
             * If this file system device is attached to some other device,
             * then we must make sure to increase the stack size for the IRP.
             * The default is +1, for the FS device itself.
             */
            FsStackOverhead = 1;
            while (FileSystemDeviceObject->AttachedDevice)
            {
                /* Get the next attached device and increase overhead */
                FileSystemDeviceObject = FileSystemDeviceObject->
                                         AttachedDevice;
                FsStackOverhead++;
            }

            /* Clear the event */
            KeClearEvent(&Event);

            /* Allocate the IRP */
            Irp = IoAllocateIrp(AttachedDeviceObject->StackSize +
                                (UCHAR)FsStackOverhead,
                                TRUE);
            if (!Irp)
            {
                /* Fail */
                Status =  STATUS_INSUFFICIENT_RESOURCES;
                break;
            }

            /* Setup the IRP */
            Irp->UserIosb = &IoStatusBlock;
            Irp->UserEvent = &Event;
            Irp->Tail.Overlay.Thread = PsGetCurrentThread();
            Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO;
            Irp->RequestorMode = KernelMode;

            /* Get the I/O Stack location and set it up */
            StackPtr = IoGetNextIrpStackLocation(Irp);
            StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
            StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
            StackPtr->Flags = AllowRawMount;
            StackPtr->Parameters.MountVolume.Vpb = DeviceObject->Vpb;
            StackPtr->Parameters.MountVolume.DeviceObject =
                AttachedDeviceObject;

            /* Save registration operations */
            RegistrationOps = IopFsRegistrationOps;

            /* Release locks */
            IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount);
            ExReleaseResourceLite(&IopDatabaseResource);

            /* Call the driver */
            Status = IoCallDriver(FileSystemDeviceObject, Irp);
            if (Status == STATUS_PENDING)
            {
                /* Wait on it */
                KeWaitForSingleObject(&Event,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      NULL);
                Status = IoStatusBlock.Status;
            }

            ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE);
            IopInterlockedDecrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount);

            /* Check if mounting was successful */
            if (NT_SUCCESS(Status))
            {
                /* Mount the VPB */
                *Vpb = IopMountInitializeVpb(DeviceObject,
                                             AttachedDeviceObject,
                                             (DeviceObject->Vpb->Flags &
                                              VPB_RAW_MOUNT));
            }
            else
            {
                /* Check if we failed because of the user */
                if ((IoIsErrorUserInduced(Status)) &&
                    (IoStatusBlock.Information == 1))
                {
                    /* Break out and fail */
                    break;
                }

                /* If there were registration operations in the meanwhile */
                if (RegistrationOps != IopFsRegistrationOps)
                {
                    /* We need to setup a local list to pickup where we left */
                    LocalList.Flink = FsList->Flink;
                    ListEntry = &LocalList;

                    Status = STATUS_UNRECOGNIZED_VOLUME;
                }

                /* Otherwise, check if we need to load the FS driver */
                if (Status == STATUS_FS_DRIVER_REQUIRED)
                {
                    /* We need to release the lock */
                    IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount);
                    ExReleaseResourceLite(&IopDatabaseResource);

                    /* Release the device lock if we're holding it */
                    if (!DeviceIsLocked)
                    {
                        KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE);
                    }

                    /* Leave critical section */
                    KeLeaveCriticalRegion();

                    /* Load the FS */
                    IopLoadFileSystemDriver(ParentFsDeviceObject);

                    /* Check if the device isn't already locked */
                    if (!DeviceIsLocked)
                    {
                        /* Lock it ourselves */
                        Status = KeWaitForSingleObject(&DeviceObject->
                                                       DeviceLock,
                                                       Executive,
                                                       KeGetPreviousMode(),
                                                       Alertable,
                                                       NULL);
                        if ((Status == STATUS_ALERTED) ||
                            (Status == STATUS_USER_APC))
                        {
                            /* Don't mount if we were interrupted */
                            ObDereferenceObject(AttachedDeviceObject);
                            return Status;
                        }
                    }

                    /* Reacquire the lock */
                    KeEnterCriticalRegion();
                    ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE);

                    /* When we released the lock, make sure nobody beat us */
                    if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
                    {
                        /* Someone did, break out */
                        Status = STATUS_SUCCESS;
                        break;
                    }

                    /* Start over by setting a failure */
                    Status = STATUS_UNRECOGNIZED_VOLUME;

                    /* We need to setup a local list to pickup where we left */
                    LocalList.Flink = FsList->Flink;
                    ListEntry = &LocalList;
                }

                /*
                 * Check if we failed with any other error then an unrecognized
                 * volume, and if this request doesn't allow mounting the raw
                 * file system.
                 */
                if (!(AllowRawMount) &&
                    (Status != STATUS_UNRECOGNIZED_VOLUME) &&
                    (FsRtlIsTotalDeviceFailure(Status)))
                {
                    /* Break out and give up */
                    break;
                }
            }

            /* Go to the next FS entry */
            ListEntry = ListEntry->Flink;
        }

        /* Dereference the device if we failed */
        if (!NT_SUCCESS(Status)) ObDereferenceObject(AttachedDeviceObject);
    }
    else if (DeviceObject->Vpb->Flags & VPB_REMOVE_PENDING)
    {
        /* Someone wants to remove us */
        Status = STATUS_DEVICE_DOES_NOT_EXIST;
    }
    else
    {
        /* Someone already mounted us */
        Status = STATUS_SUCCESS;
    }

    /* Release the FS lock */
    ExReleaseResourceLite(&IopDatabaseResource);
    KeLeaveCriticalRegion();

    /* Release the device lock if we're holding it */
    if (!DeviceIsLocked) KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE);

    /* Check if we failed to mount the boot partition */
    if ((!NT_SUCCESS(Status)) &&
        (DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) &&
        ExpInitializationPhase < 2)
    {
        /* Bugcheck the system */
        KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
                     (ULONG_PTR)DeviceObject,
                     Status,
                     0,
                     0);
    }

    /* Return the mount status */
    return Status;
}
示例#2
0
NTSTATUS
FatProcessException (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp,
    IN NTSTATUS ExceptionCode
    )

/*++

Routine Description:

    This routine process an exception.  It either completes the request
    with the saved exception status or it sends it off to IoRaiseHardError()

Arguments:

    Irp - Supplies the Irp being processed

    ExceptionCode - Supplies the normalized exception status being handled

Return Value:

    NTSTATUS - Returns the results of either posting the Irp or the
        saved completion status.

--*/

{
    PVCB Vcb;
    PIO_STACK_LOCATION IrpSp;
    FAT_VOLUME_STATE TransitionState = VolumeDirty;
    ULONG SavedFlags;

    DebugTrace(0, Dbg, "FatProcessException\n", 0);

    //
    //  If there is not an irp context, we must have had insufficient resources.
    //

    if ( !ARGUMENT_PRESENT( IrpContext ) ) {

        FatCompleteRequest( FatNull, Irp, ExceptionCode );

        return ExceptionCode;
    }

    //
    //  Get the real exception status from IrpContext->ExceptionStatus, and
    //  reset it.
    //

    ExceptionCode = IrpContext->ExceptionStatus;
    FatResetExceptionState( IrpContext );

    //
    //  If this is an Mdl write request, then take care of the Mdl
    //  here so that things get cleaned up properly.  Cc now leaves
    //  the MDL in place so a filesystem can retry after clearing an
    //  internal condition (FAT does not).
    //

#if __NDAS_FAT_WIN2K_SUPPORT__

    if (NdFatCcMdlWriteAbort &&
		(IrpContext->MajorFunction == IRP_MJ_WRITE) &&
        (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) &&
        (Irp->MdlAddress != NULL)) {

        PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp);

        NdFatCcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress );
        Irp->MdlAddress = NULL;
    }

#else

    if ((IrpContext->MajorFunction == IRP_MJ_WRITE) &&
        (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) &&
        (Irp->MdlAddress != NULL)) {

        PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp);

        CcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress );
        Irp->MdlAddress = NULL;
    }

#endif

    //
    //  If we are going to post the request, we may have to lock down the
    //  user's buffer, so do it here in a try except so that we failed the
    //  request if the LockPages fails.
    //
    //  Also unpin any repinned Bcbs, protected by the try {} except {} filter.
    //

    try {

        SavedFlags = IrpContext->Flags;

        //
        //  Make sure we don't try to write through Bcbs
        //

        SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH);

        FatUnpinRepinnedBcbs( IrpContext );

        IrpContext->Flags = SavedFlags;

        //
        //  If we will have to post the request, do it here.  Note
        //  that the last thing FatPrePostIrp() does is mark the Irp pending,
        //  so it is critical that we actually return PENDING.  Nothing
        //  from this point to return can fail, so we are OK.
        //
        //  We cannot do a verify operations at APC level because we
        //  have to wait for Io operations to complete.
        //

#if __NDAS_FAT__

        if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) &&
            (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (KeGetCurrentIrql() >= APC_LEVEL)) ||
			(!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) && ExceptionCode == STATUS_CANT_WAIT))) {

            ExceptionCode = FatFsdPostRequest( IrpContext, Irp );
        }

#else
        
		if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) &&
            (((ExceptionCode == STATUS_VERIFY_REQUIRED) && (KeGetCurrentIrql() >= APC_LEVEL)) ||
             (ExceptionCode == STATUS_CANT_WAIT))) {

            ExceptionCode = FatFsdPostRequest( IrpContext, Irp );
        }

#endif

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

        ExceptionCode = IrpContext->ExceptionStatus;
        IrpContext->ExceptionStatus = 0;

        IrpContext->Flags = SavedFlags;
    }

    //
    //  If we posted the request, just return here.
    //

    if (ExceptionCode == STATUS_PENDING) {

        return ExceptionCode;
    }

    Irp->IoStatus.Status = ExceptionCode;

    //
    //  If this request is not a "top-level" irp, just complete it.
    //

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

        //
        //  If there is a cache operation above us, commute verify
        //  to a lock conflict.  This will cause retries so that
        //  we have a chance of getting through without needing
        //  to return an unaesthetic error for the operation.
        //

        if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP &&
            ExceptionCode == STATUS_VERIFY_REQUIRED) {

            ExceptionCode = STATUS_FILE_LOCK_CONFLICT;
        }
        
        FatCompleteRequest( IrpContext, Irp, ExceptionCode );

        return ExceptionCode;
    }

    if (IoIsErrorUserInduced(ExceptionCode)) {

        //
        //  Check for the various error conditions that can be caused by,
        //  and possibly resolved by the user.
        //

        if (ExceptionCode == STATUS_VERIFY_REQUIRED) {

            PDEVICE_OBJECT Device;

            DebugTrace(0, Dbg, "Perform Verify Operation\n", 0);

            //
            //  Now we are at the top level file system entry point.
            //
            //  Grab the device to verify from the thread local storage
            //  and stick it in the information field for transportation
            //  to the fsp.  We also clear the field at this time.
            //

            Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
            IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );

            if ( Device == NULL ) {

                Device = IoGetDeviceToVerify( PsGetCurrentThread() );
                IoSetDeviceToVerify( PsGetCurrentThread(), NULL );

                ASSERT( Device != NULL );
            }

            //
            //  Let's not BugCheck just because the driver messed up.
            //

            if (Device == NULL) {

                ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;

                FatCompleteRequest( IrpContext, Irp, ExceptionCode );

                return ExceptionCode;
            }

            //
            //  FatPerformVerify() will do the right thing with the Irp.

            return FatPerformVerify( IrpContext, Irp, Device );
        }

        //
        //  The other user induced conditions generate an error unless
        //  they have been disabled for this request.
        //

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

            FatCompleteRequest( IrpContext, Irp, ExceptionCode );

            return ExceptionCode;

        } else {

            //
            //  Generate a pop-up
            //

            PDEVICE_OBJECT RealDevice;
            PVPB Vpb;
            PETHREAD Thread;

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

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

            } else {

                Vpb = NULL;
            }

            //
            //  The device to verify is either in my thread local storage
            //  or that of the thread that owns the Irp.
            //

            Thread = Irp->Tail.Overlay.Thread;
            RealDevice = IoGetDeviceToVerify( Thread );

            if ( RealDevice == NULL ) {

                Thread = PsGetCurrentThread();
                RealDevice = IoGetDeviceToVerify( Thread );

                ASSERT( RealDevice != NULL );
            }

            //
            //  Let's not BugCheck just because the driver messed up.
            //

            if (RealDevice == NULL) {

                FatCompleteRequest( IrpContext, Irp, ExceptionCode );

                return ExceptionCode;
            }

            //
            //  This routine actually causes the pop-up.  It usually
            //  does this by queuing an APC to the callers thread,
            //  but in some cases it will complete the request immediately,
            //  so it is very important to IoMarkIrpPending() first.
            //

            IoMarkIrpPending( Irp );
            IoRaiseHardError( Irp, Vpb, RealDevice );

            //
            //  We will be handing control back to the caller here, so
            //  reset the saved device object.
            //

            IoSetDeviceToVerify( Thread, NULL );

            //
            //  The Irp will be completed by Io or resubmitted.  In either
            //  case we must clean up the IrpContext here.
            //

            FatDeleteIrpContext( IrpContext );
            return STATUS_PENDING;
        }
    }

    //
    //  This is just a run of the mill error.  If is a STATUS that we
    //  raised ourselves, and the information would be use for the
    //  user, raise an informational pop-up.
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );
    Vcb = IrpContext->Vcb;

    //
    //  Now, if the Vcb is unknown to us this means that the error was raised
    //  in the process of a mount and before we even had a chance to build
    //  a full Vcb - and was really handled there.
    //

    if (Vcb != NULL) {

        if ( !FatDeviceIsFatFsdo( IrpSp->DeviceObject) &&
             !NT_SUCCESS(ExceptionCode) &&
             !FsRtlIsTotalDeviceFailure(ExceptionCode) ) {

            TransitionState = VolumeDirtyWithSurfaceTest;
        }

        //
        //  If this was a STATUS_FILE_CORRUPT or similar error indicating some
        //  nastiness out on the media, then mark the volume permanently dirty.
        //

        if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS) &&
            ( TransitionState == VolumeDirtyWithSurfaceTest ||
              (ExceptionCode == STATUS_FILE_CORRUPT_ERROR) ||
              (ExceptionCode == STATUS_DISK_CORRUPT_ERROR) ||
              (ExceptionCode == STATUS_EA_CORRUPT_ERROR) ||
              (ExceptionCode == STATUS_INVALID_EA_NAME) ||
              (ExceptionCode == STATUS_EA_LIST_INCONSISTENT) ||
              (ExceptionCode == STATUS_NO_EAS_ON_FILE) )) {

            ASSERT( NodeType(Vcb) == FAT_NTC_VCB );

            SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY );

            //
            //  Do the "dirty" work, ignoring any error.
            //

            try {

                FatMarkVolume( IrpContext, Vcb, TransitionState );

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

                NOTHING;
            }
        }
    }