BOOLEAN RawCheckForDismount ( PVCB Vcb, BOOLEAN CalledFromCreate ) /*++ Routine Description: This routine determines if a volume is ready for deletion. It correctly synchronizes with creates en-route to the file system. On exit if the vcb is deleted the mutex is released Arguments: Vcb - Supplies the value to examine CalledFromCreate - Tells us if we should allow 0 or 1 in VpbRefCount Return Value: BOOLEAN - TRUE if the volume was deleted, FALSE otherwise. --*/ { KIRQL SavedIrql; ULONG ReferenceCount = 0; BOOLEAN DeleteVolume = FALSE; // // We must enter with the vcb mutex acquired // ASSERT( KeReadStateMutant( &Vcb->Mutex ) == 0 ); IoAcquireVpbSpinLock( &SavedIrql ); ReferenceCount = Vcb->Vpb->ReferenceCount; { PVPB Vpb; Vpb = Vcb->Vpb; // // If a create is in progress on this volume, don't // delete it. // if ( ReferenceCount != (ULONG)(CalledFromCreate ? 1 : 0) ) { // // Cleanup the vpb on a forced dismount even if we can't delete the vcb if // we haven't already done so // if ((Vcb->SpareVpb != NULL) && FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNTED )) { // // Setup the spare vpb and put it on the real device // RtlZeroMemory( Vcb->SpareVpb, sizeof( VPB ) ); Vcb->SpareVpb->Type = IO_TYPE_VPB; Vcb->SpareVpb->Size = sizeof( VPB ); Vcb->SpareVpb->RealDevice = Vcb->Vpb->RealDevice; Vcb->SpareVpb->DeviceObject = NULL; Vcb->SpareVpb->Flags = FlagOn( Vcb->Vpb->Flags, VPB_REMOVE_PENDING ); Vcb->Vpb->RealDevice->Vpb = Vcb->SpareVpb; // // The spare vpb now belongs to the iosubsys and we own the original one // Vcb->SpareVpb = NULL; Vcb->Vpb->Flags |= VPB_PERSISTENT; } DeleteVolume = FALSE; } else { DeleteVolume = TRUE; if ( Vpb->RealDevice->Vpb == Vpb ) { Vpb->DeviceObject = NULL; Vpb->Flags &= ~VPB_MOUNTED; } } } IoReleaseVpbSpinLock( SavedIrql ); if (DeleteVolume) { (VOID)KeReleaseMutex( &Vcb->Mutex, FALSE ); // // Free the spare vpb if we didn't use it or the original one if // we did use it and there are no more reference counts. Otherwise i/o // subsystem still has a ref and will free the vpb itself // if (Vcb->SpareVpb) { ExFreePool( Vcb->SpareVpb ); } else if (ReferenceCount == 0) { ExFreePool( Vcb->Vpb ); } ObDereferenceObject( Vcb->TargetDeviceObject ); IoDeleteDevice( (PDEVICE_OBJECT)CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb)); } return DeleteVolume; }
NTSTATUS NtQueryMutant ( IN HANDLE MutantHandle, IN MUTANT_INFORMATION_CLASS MutantInformationClass, OUT PVOID MutantInformation, IN ULONG MutantInformationLength, OUT PULONG ReturnLength OPTIONAL ) /*++ Routine Description: This function queries the state of a mutant object and returns the requested information in the specified record structure. Arguments: MutantHandle - Supplies a handle to a mutant object. MutantInformationClass - Supplies the class of information being requested. MutantInformation - Supplies a pointer to a record that is to receive the requested information. MutantInformationLength - Supplies the length of the record that is to receive the requested information. ReturnLength - Supplies an optional pointer to a variable that will receive the actual length of the information that is returned. Return Value: TBS --*/ { BOOLEAN Abandoned; BOOLEAN OwnedByCaller; LONG Count; PVOID Mutant; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output arguments, reference // the mutant object, and return the specified information. If the probe // fails, then return the exception code as the service status. Otherwise // return the status value returned by the reference object by handle // routine. // try { // // Get previous processor mode and probe output arguments if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWrite(MutantInformation, sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG)); if (ARGUMENT_PRESENT(ReturnLength)) { ProbeForWriteUlong(ReturnLength); } } // // Check argument validity. // if (MutantInformationClass != MutantBasicInformation) { return STATUS_INVALID_INFO_CLASS; } if (MutantInformationLength != sizeof(MUTANT_BASIC_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } // // Reference mutant object by handle. // Status = ObReferenceObjectByHandle(MutantHandle, MUTANT_QUERY_STATE, ExMutantObjectType, PreviousMode, &Mutant, NULL); // // If the reference was successful, then read the current state and // abandoned status of the mutant object, dereference mutant object, // fill in the information structure, and return the length of the // information structure if specified. If the write of the mutant // information or the return length fails, then do not report an error. // When the caller accesses the information structure or length an // access violation will occur. // if (NT_SUCCESS(Status)) { Count = KeReadStateMutant((PKMUTANT)Mutant); Abandoned = ((PKMUTANT)Mutant)->Abandoned; OwnedByCaller = (BOOLEAN)((((PKMUTANT)Mutant)->OwnerThread == KeGetCurrentThread())); ObDereferenceObject(Mutant); try { ((PMUTANT_BASIC_INFORMATION)MutantInformation)->CurrentCount = Count; ((PMUTANT_BASIC_INFORMATION)MutantInformation)->OwnedByCaller = OwnedByCaller; ((PMUTANT_BASIC_INFORMATION)MutantInformation)->AbandonedState = Abandoned; if (ARGUMENT_PRESENT(ReturnLength)) { *ReturnLength = sizeof(MUTANT_BASIC_INFORMATION); } } except(ExSystemExceptionFilter()) { } } // // If an exception occurs during the probe of the output arguments, then // always handle the exception and return the exception code as the status // value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }