Пример #1
0
NTSTATUS
FatCommonDeviceControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for doing Device control operations called
    by both the fsd and fsp threads

Arguments:

    Irp - Supplies the Irp to process

    InFsp - Indicates if this is the fsp thread or someother thread

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;
    KEVENT WaitEvent;
    PVOID CompletionContext = NULL;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);

    //
    //  Decode the file object, the only type of opens we accept are
    //  user volume opens.
    //

    if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );

        DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER);
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  A few IOCTLs actually require some intervention on our part
    //

    switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {

    case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:

        //
        //  This is sent by the Volume Snapshot driver (Lovelace).
        //  We flush the volume, and hold all file resources
        //  to make sure that nothing more gets dirty. Then we wait
        //  for the IRP to complete or cancel.
        //

        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
        FatAcquireExclusiveVolume( IrpContext, Vcb );

        FatFlushAndCleanVolume( IrpContext,
                                Irp,
                                Vcb,
                                FlushWithoutPurge );

        KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE );
        CompletionContext = &WaitEvent;

        //
        //  Get the next stack location, and copy over the stack location
        //

        IoCopyCurrentIrpStackLocationToNext( Irp );

        //
        //  Set up the completion routine
        //

        IoSetCompletionRoutine( Irp,
                                FatDeviceControlCompletionRoutine,
                                CompletionContext,
                                TRUE,
                                TRUE,
                                TRUE );
        break;

    default:

        //
        //  FAT doesn't need to see this on the way back, so skip ourselves.
        //

        IoSkipCurrentIrpStackLocation( Irp );
        break;
    }

    //
    //  Send the request.
    //

    Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);

    if (Status == STATUS_PENDING && CompletionContext) {

        KeWaitForSingleObject( &WaitEvent,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL );

        Status = Irp->IoStatus.Status;
    }

    //
    //  If we had a context, the IRP remains for us and we will complete it.
    //  Handle it appropriately.
    //

    if (CompletionContext) {

        //
        //  Release all the resources that we held because of a
        //  VOLSNAP_FLUSH_AND_HOLD. 
        //

        ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES );

        FatReleaseVolume( IrpContext, Vcb );

        //
        //  If we had no context, the IRP will complete asynchronously.
        //

    } else {

        Irp = NULL;
    }

    FatCompleteRequest( IrpContext, Irp, Status );

    DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status);

    return Status;
}
Пример #2
0
__drv_mustHoldCriticalRegion    
NTSTATUS
FatCommonShutdown (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for shutdown called by both the fsd and
    fsp threads.

Arguments:

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    KEVENT Event;
    PLIST_ENTRY Links;
    PVCB Vcb;
    PIRP NewIrp;
    IO_STATUS_BLOCK Iosb;
    BOOLEAN VcbDeleted;

    PAGED_CODE();

    //
    //  Make sure we don't get any pop-ups, and write everything through.
    //

    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS |
                               IRP_CONTEXT_FLAG_WRITE_THROUGH);

    //
    //  Initialize an event for doing calls down to
    //  our target device objects.
    //

    KeInitializeEvent( &Event, NotificationEvent, FALSE );

    //
    //  Indicate that shutdown has started.  This is used in FatFspClose.
    //

    FatData.ShutdownStarted = TRUE;    

    //
    //  Get everyone else out of the way
    //
    
    ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );

#pragma prefast( push )
#pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
#pragma prefast( disable: 28193, "this will always wait" )

    (VOID) FatAcquireExclusiveGlobal( IrpContext );

#pragma prefast( pop )

    try {

        //
        //  For every volume that is mounted we will flush the
        //  volume and then shutdown the target device objects.
        //

        Links = FatData.VcbQueue.Flink;
        while (Links != &FatData.VcbQueue) {

            Vcb = CONTAINING_RECORD(Links, VCB, VcbLinks);

            Links = Links->Flink;

            //
            //  If we have already been called before for this volume
            //  (and yes this does happen), skip this volume as no writes
            //  have been allowed since the first shutdown.
            //

            if ( FlagOn( Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ||
                 (Vcb->VcbCondition != VcbGood) ) {

                continue;
            }

            FatAcquireExclusiveVolume( IrpContext, Vcb );

            try {

                (VOID)FatFlushVolume( IrpContext, Vcb, Flush );

                //
                //  The volume is now clean, note it.  We purge the
                //  volume file cache map before marking the volume
                //  clean incase there is a stale Bpb in the cache.
                //

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

                    CcPurgeCacheSection( &Vcb->SectionObjectPointers,
                                         NULL,
                                         0,
                                         FALSE );

                    FatMarkVolume( IrpContext, Vcb, VolumeClean );
                }

            } except( EXCEPTION_EXECUTE_HANDLER ) {

                  FatResetExceptionState( IrpContext );
            }

            //
            //  Sometimes we take an excepion while flushing the volume, such
            //  as when autoconv has converted the volume and is rebooting.
            //  Even in that case we want to send the shutdown irp to the
            //  target device so it can know to flush its cache, if it has one.
            //

            try {

                NewIrp = IoBuildSynchronousFsdRequest( IRP_MJ_SHUTDOWN,
                                                       Vcb->TargetDeviceObject,
                                                       NULL,
                                                       0,
                                                       NULL,
                                                       &Event,
                                                       &Iosb );

                if (NewIrp != NULL) {

                    if (NT_SUCCESS(IoCallDriver( Vcb->TargetDeviceObject, NewIrp ))) {

                        (VOID) KeWaitForSingleObject( &Event,
                                                      Executive,
                                                      KernelMode,
                                                      FALSE,
                                                      NULL );

                        KeClearEvent( &Event );
                    }
                }

            } except( EXCEPTION_EXECUTE_HANDLER ) {

                  FatResetExceptionState( IrpContext );
            }

            SetFlag( Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN );

            //
            //  Attempt to punch the volume down.
            //

            VcbDeleted = FatCheckForDismount( IrpContext,
                                              Vcb,
                                              FALSE );

            if (!VcbDeleted) {
                
#pragma prefast( suppress:28107, "prefast is having trouble figuring out that Vcb is acquired" )
                FatReleaseVolume( IrpContext, Vcb );
            }
        }

    } finally {

        FatReleaseGlobal( IrpContext );

        //
        //  Unregister the file system.
        //
        
        IoUnregisterFileSystem( FatDiskFileSystemDeviceObject);
        IoUnregisterFileSystem( FatCdromFileSystemDeviceObject);
        IoDeleteDevice( FatDiskFileSystemDeviceObject);
        IoDeleteDevice( FatCdromFileSystemDeviceObject);

        FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
    }

    //
    //  And return to our caller
    //

    DebugTrace(-1, Dbg, "FatFsdShutdown -> STATUS_SUCCESS\n", 0);

    return STATUS_SUCCESS;
}
Пример #3
0
NTSTATUS
FatCommonDeviceControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for doing Device control operations called
    by both the fsd and fsp threads

Arguments:

    Irp - Supplies the Irp to process

    InFsp - Indicates if this is the fsp thread or someother thread

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;
    KEVENT WaitEvent;
    PVOID CompletionContext = NULL;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

#if __NDAS_FAT_PRIMARY__

	if (IrpContext->MajorFunction == IRP_MJ_DEVICE_CONTROL && 
		IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode == IOCTL_INSERT_PRIMARY_SESSION) {

		PVOLUME_DEVICE_OBJECT	VolDo = CONTAINING_RECORD( IoGetCurrentIrpStackLocation(Irp)->DeviceObject, 
														   VOLUME_DEVICE_OBJECT, 
														   DeviceObject );
		PSESSION_INFORMATION	inputBuffer = (PSESSION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
		ULONG					inputBufferLength = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.InputBufferLength;
		ULONG					outputBufferLength;
		PULONG					outputBuffer;
		PPRIMARY_SESSION		primarySession;

		if (inputBufferLength != sizeof(SESSION_INFORMATION)) {

			FatCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_PARAMETER );
			return Status;
		} 

		outputBufferLength = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.OutputBufferLength;
		outputBuffer = (PULONG)Irp->AssociatedIrp.SystemBuffer;

		primarySession = PrimarySession_Create( IrpContext, VolDo, inputBuffer, Irp );

		ASSERT( primarySession );

		FatCompleteRequest( IrpContext, NULL, 0 );
		Status = STATUS_PENDING;
		return Status;
	}

#endif

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);

    //
    //  Decode the file object, the only type of opens we accept are
    //  user volume opens.
    //

    if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );

        DebugTrace(-1, Dbg2, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER);
        return STATUS_INVALID_PARAMETER;
    }

#define IOCTL_VOLUME_BASE   ((ULONG) 'V')
#define MOUNTDEVCONTROLTYPE  ((ULONG) 'M')

	DebugTrace2( 0, Dbg2, 
				("FatCommonDeviceControl: deviceType = %d, function = %d IOCTL_VOLUME_BASE = %d, MOUNTDEVCONTROLTYPE = %d\n",
				  DEVICE_TYPE_FROM_CTL_CODE(IrpSp->Parameters.DeviceIoControl.IoControlCode), 
				  (UCHAR)((IrpSp->Parameters.DeviceIoControl.IoControlCode & 0x00003FFC) >> 2), IOCTL_VOLUME_BASE, MOUNTDEVCONTROLTYPE) );

#if __NDAS_FAT__
	if (CONTAINING_RECORD(Vcb, VOLUME_DEVICE_OBJECT, Vcb)->NetdiskEnableMode == NETDISK_SECONDARY)
		SetFlag( IrpContext->NdFatFlags, ND_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT );
#endif

    //
    //  A few IOCTLs actually require some intervention on our part
    //

    switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {

    case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:


#if __NDAS_FAT_WIN2K_SUPPORT__

		if (!IS_WINDOWSXP_OR_LATER()) {

			ASSERT( FALSE );
			IoSkipCurrentIrpStackLocation( Irp );
			break;
		}

#endif

        //
        //  This is sent by the Volume Snapshot driver (Lovelace).
        //  We flush the volume, and hold all file resources
        //  to make sure that nothing more gets dirty. Then we wait
        //  for the IRP to complete or cancel.
        //

        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
        FatAcquireExclusiveVolume( IrpContext, Vcb );

		FatFlushAndCleanVolume( IrpContext,
                                Irp,
                                Vcb,
                                FlushWithoutPurge );

        KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE );
        CompletionContext = &WaitEvent;

        //
        //  Get the next stack location, and copy over the stack location
        //

        IoCopyCurrentIrpStackLocationToNext( Irp );

        //
        //  Set up the completion routine
        //

        IoSetCompletionRoutine( Irp,
                                FatDeviceControlCompletionRoutine,
                                CompletionContext,
                                TRUE,
                                TRUE,
                                TRUE );
        break;

    default:

        //
        //  FAT doesn't need to see this on the way back, so skip ourselves.
        //

        IoSkipCurrentIrpStackLocation( Irp );
        break;
    }

    //
    //  Send the request.
    //

    Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);

    if (Status == STATUS_PENDING && CompletionContext) {

        KeWaitForSingleObject( &WaitEvent,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL );

        Status = Irp->IoStatus.Status;
    }

	//DebugTrace(-1, Dbg2, "FatCommonDeviceControl -> Information %08lx\n", Irp->IoStatus.Information);

    //
    //  If we had a context, the IRP remains for us and we will complete it.
    //  Handle it appropriately.
    //

    if (CompletionContext) {

        //
        //  Release all the resources that we held because of a
        //  VOLSNAP_FLUSH_AND_HOLD. 
        //

        ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES );

        FatReleaseVolume( IrpContext, Vcb );

        //
        //  If we had no context, the IRP will complete asynchronously.
        //

    } else {

        Irp = NULL;
    }

	FatCompleteRequest( IrpContext, Irp, Status );

    DebugTrace(-1, Dbg2, "FatCommonDeviceControl -> %08lx\n", Status);

    return Status;
}
Пример #4
0
NTSTATUS
FatCommonDeviceControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for doing Device control operations called
    by both the fsd and fsp threads

Arguments:

    Irp - Supplies the Irp to process

    InFsp - Indicates if this is the fsp thread or someother thread

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;
    KEVENT WaitEvent;
    PVOID CompletionContext = NULL;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    PAGED_CODE();

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %p\n", Irp);
    DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);

    //
    //  Decode the file object, the only type of opens we accept are
    //  user volume opens.
    //

    if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );

        DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER);
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  A few IOCTLs actually require some intervention on our part
    //

    switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {

    case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:

        //
        //  This is sent by the Volume Snapshot driver (Lovelace).
        //  We flush the volume, and hold all file resources
        //  to make sure that nothing more gets dirty. Then we wait
        //  for the IRP to complete or cancel.
        //

        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
        FatAcquireExclusiveVolume( IrpContext, Vcb );

        FatFlushAndCleanVolume( IrpContext,
                                Irp,
                                Vcb,
                                FlushWithoutPurge );

        KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE );
        CompletionContext = &WaitEvent;

        //
        //  Get the next stack location, and copy over the stack location
        //

        IoCopyCurrentIrpStackLocationToNext( Irp );

        //
        //  Set up the completion routine
        //

        IoSetCompletionRoutine( Irp,
                                FatDeviceControlCompletionRoutine,
                                CompletionContext,
                                TRUE,
                                TRUE,
                                TRUE );
        break;

    case IOCTL_DISK_COPY_DATA:

        //
        //  We cannot allow this IOCTL to be sent unless the volume is locked,
        //  since this IOCTL allows direct writing of data to the volume.
        //  We do allow kernel callers to force access via a flag.  A handle that
        //  issued a dismount can send this IOCTL as well.
        //

        if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) &&
            !FlagOn( IrpSp->Flags, SL_FORCE_DIRECT_WRITE ) &&
            !FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) {

            FatCompleteRequest( IrpContext,
                                Irp,
                                STATUS_ACCESS_DENIED );

            DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED);
            return STATUS_ACCESS_DENIED;
        }

        break;

    case IOCTL_SCSI_PASS_THROUGH:
    case IOCTL_SCSI_PASS_THROUGH_DIRECT:
    case IOCTL_SCSI_PASS_THROUGH_EX:
    case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX:

        //
        //  If someone is issuing a format unit command underneath us, then make
        //  sure we mark the device as needing verification when they close their
        //  handle.
        //

        if ((!FlagOn( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ) ||
             !FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) &&
             (Irp->AssociatedIrp.SystemBuffer != NULL)) {

            PCDB  Cdb = NULL;

            //
            //  If this is a 32 bit application running on 64 bit then thunk the
            //  input structures to grab the Cdb.
            //

#if defined (_WIN64) && defined(BUILD_WOW64_ENABLED)
            if (IoIs32bitProcess(Irp)) {

                if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) ||
                     (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) {

                    if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32 )) {

                        Cdb = (PCDB)((PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
                    }
                } else {

                    if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32_EX )) {

                        Cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
                    }
                }

            } else {
#endif
                if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) ||
                     (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) {

                    if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH )) {

                        Cdb = (PCDB)((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
                    }
                } else {

                    if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH_EX )) {

                        Cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
                    }
                }

#if defined (_WIN64) && defined(BUILD_WOW64_ENABLED)
            }
#endif

            if ((Cdb != NULL) && (Cdb->AsByte[0] == SCSIOP_FORMAT_UNIT)) {

                SetFlag( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT );
                SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED );
            }
        }

        //
        //  Fall through as we do not need to know the outcome of this operation.
        //

    default:

        //
        //  FAT doesn't need to see this on the way back, so skip ourselves.
        //

        IoSkipCurrentIrpStackLocation( Irp );
        break;
    }

    //
    //  Send the request.
    //

    Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);

    if (Status == STATUS_PENDING && CompletionContext) {

        KeWaitForSingleObject( &WaitEvent,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL );

        Status = Irp->IoStatus.Status;
    }

    //
    //  If we had a context, the IRP remains for us and we will complete it.
    //  Handle it appropriately.
    //

    if (CompletionContext) {

        //
        //  Release all the resources that we held because of a
        //  VOLSNAP_FLUSH_AND_HOLD. 
        //

        NT_ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES );

        FatReleaseVolume( IrpContext, Vcb );

        //
        //  If we had no context, the IRP will complete asynchronously.
        //

    } else {

        Irp = NULL;
    }

    FatCompleteRequest( IrpContext, Irp, Status );

    DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status);

    return Status;
}