NTSTATUS NdFatCommonFlushBuffers ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for flushing a buffer. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; BOOLEAN VcbAcquired = FALSE; BOOLEAN FcbAcquired = FALSE; PDIRENT Dirent; PBCB DirentBcb = NULL; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; PAGED_CODE(); IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject); // // Extract and decode the file object // FileObject = IrpSp->FileObject; TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); // // CcFlushCache is always synchronous, so if we can't wait enqueue // the irp to the Fsp. // if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) { Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status ); return Status; } Status = STATUS_SUCCESS; try { if (!FlagOn(Ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { do { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->Secondary->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); if (secondaryRequest == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, IrpContext->OriginatingIrp, IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), Ccb->PrimaryFileHandle ); ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { ASSERT( NDFAT_BUG ); break; } KeClearEvent (&secondaryRequest->CompleteEvent); if (BooleanFlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) { ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; ASSERT(ndfsWinxpReplytHeader->Status == STATUS_SUCCESS); } if (secondaryRequest) { DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } if ( secondarySessionResourceAcquired == TRUE ) { SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); secondarySessionResourceAcquired = FALSE; } break; } while(0); } Status = STATUS_SUCCESS; // // Case on the type of open that we are trying to flush // switch (TypeOfOpen) { case VirtualVolumeFile: case EaFile: case DirectoryFile: DebugTrace(0, Dbg, "Flush that does nothing\n", 0); break; case UserFileOpen: DebugTrace(0, Dbg, "Flush User File Open\n", 0); (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); FcbAcquired = TRUE; FatVerifyFcb( IrpContext, Fcb ); // // If the file is cached then flush its cache // Status = FatFlushFile( IrpContext, Fcb, Flush ); // // Also update and flush the file's dirent in the parent directory if the // file flush worked. // if (NT_SUCCESS( Status )) { // // Insure that we get the filesize to disk correctly. This is // benign if it was already good. // // (why do we need to do this?) // SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); #if 0 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); #endif // // Flush the volume file to get any allocation information // updates to disk. // if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) { Status = FatFlushFat( IrpContext, Vcb ); ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT); } // // Set the write through bit so that these modifications // will be completed with the request. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); } break; case UserDirectoryOpen: // // If the user had opened the root directory then we'll // oblige by flushing the volume. // if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) { DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0); break; } case UserVolumeOpen: DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0); // // Acquire exclusive access to the Vcb. // { BOOLEAN Finished; Finished = FatAcquireExclusiveSecondaryVcb( IrpContext, Vcb ); ASSERT( Finished ); } VcbAcquired = TRUE; // // Mark the volume clean and then flush the volume file, // and then all directories // Status = FatFlushVolume( IrpContext, Vcb, Flush ); // // If the volume was dirty, do the processing that the delayed // callback would have done. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) { // // Cancel any pending clean volumes. // (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc ); // // The volume is now clean, note it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { FatMarkVolume( IrpContext, Vcb, VolumeClean ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); } // // Unlock the volume if it is removable. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); } } break; default: FatBugCheck( TypeOfOpen, 0, 0 ); } FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinRepinnedBcbs( IrpContext ); } finally { DebugUnwind( FatCommonFlushBuffers ); if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); if (secondarySessionResourceAcquired) { SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); } FatUnpinBcb( IrpContext, DirentBcb ); if (VcbAcquired) { FatReleaseSecondaryVcb( IrpContext, Vcb ); } if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); } // // If this is a normal termination then pass the request on // to the target device object. // if (!AbnormalTermination()) { NTSTATUS DriverStatus; PIO_STACK_LOCATION NextIrpSp; // // Get the next stack location, and copy over the stack location // NextIrpSp = IoGetNextIrpStackLocation( Irp ); *NextIrpSp = *IrpSp; // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatFlushCompletionRoutine, ULongToPtr( Status ), TRUE, TRUE, TRUE ); // // Send the request. // DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp); Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ? Status : DriverStatus; // // Free the IrpContext and return to the caller. // FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS ); } DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status); } return Status; }
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; } } }
NTSTATUS FatSetFsLabelInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer ) /*++ Routine Description: This routine implements the set volume label call Arguments: Vcb - Supplies the Vcb being queried Buffer - Supplies the input where the information is stored. Return Value: NTSTATUS - Returns the status for the operation --*/ { NTSTATUS Status; PDIRENT Dirent; PBCB DirentBcb = NULL; ULONG ByteOffset; WCHAR TmpBuffer[11]; UCHAR OemBuffer[11]; OEM_STRING OemLabel; UNICODE_STRING UnicodeString; UNICODE_STRING UpcasedLabel; DebugTrace(+1, Dbg, "FatSetFsLabelInfo...\n", 0); // // Setup our local variable // UnicodeString.Length = (USHORT)Buffer->VolumeLabelLength; UnicodeString.MaximumLength = UnicodeString.Length; UnicodeString.Buffer = (PWSTR) &Buffer->VolumeLabel[0]; // // Make sure the name can fit into the stack buffer // if ( UnicodeString.Length > 11*sizeof(WCHAR) ) { return STATUS_INVALID_VOLUME_LABEL; } // // Upcase the name and convert it to the Oem code page. // OemLabel.Buffer = &OemBuffer[0]; OemLabel.Length = 0; OemLabel.MaximumLength = 11; Status = RtlUpcaseUnicodeStringToCountedOemString( &OemLabel, &UnicodeString, FALSE ); // // Volume label that fits in 11 unicode character length limit // is not necessary within 11 characters in OEM character set. // if (!NT_SUCCESS( Status )) { DebugTrace(-1, Dbg, "FatSetFsLabelInfo: Label must be too long. %08lx\n", Status ); return STATUS_INVALID_VOLUME_LABEL; } // // Strip spaces off of the label. // if (OemLabel.Length > 0) { USHORT i; USHORT LastSpaceIndex = MAXUSHORT; // // Check the label for illegal characters // for ( i = 0; i < (ULONG)OemLabel.Length; i += 1 ) { if ( FsRtlIsLeadDbcsCharacter( OemLabel.Buffer[i] ) ) { LastSpaceIndex = MAXUSHORT; i += 1; continue; } if (!FsRtlIsAnsiCharacterLegalFat(OemLabel.Buffer[i], FALSE) || (OemLabel.Buffer[i] == '.')) { return STATUS_INVALID_VOLUME_LABEL; } // // Watch for the last run of spaces, so we can strip them. // if (OemLabel.Buffer[i] == ' ' && LastSpaceIndex == MAXUSHORT) { LastSpaceIndex = i; } else { LastSpaceIndex = MAXUSHORT; } } if (LastSpaceIndex != MAXUSHORT) { OemLabel.Length = LastSpaceIndex; } } // // Get the Unicode upcased string to store in the VPB. // UpcasedLabel.Length = UnicodeString.Length; UpcasedLabel.MaximumLength = 11*sizeof(WCHAR); UpcasedLabel.Buffer = &TmpBuffer[0]; Status = RtlOemStringToCountedUnicodeString( &UpcasedLabel, &OemLabel, FALSE ); if (!NT_SUCCESS( Status )) { DebugTrace(-1, Dbg, "FatSetFsLabelInfo: Label must be too long. %08lx\n", Status ); return STATUS_INVALID_VOLUME_LABEL; } DirentBcb = NULL; // // Make this look like a write through to disk. This is important to // avoid a unpleasant window where it looks like we have the wrong volume. // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH ); try { // // Are we setting or removing the label? Note that shaving spaces could // make this different than wondering if the input buffer is non-zero length. // if (OemLabel.Length > 0) { // // Locate the volume label if there already is one // FatLocateVolumeLabel( IrpContext, Vcb, &Dirent, &DirentBcb, &ByteOffset ); // // Check that we really got one, if not then we need to create // a new one. The procedure we call will raise an appropriate // status if we are not able to allocate a new dirent // if (Dirent == NULL) { ByteOffset = FatCreateNewDirent( IrpContext, Vcb->RootDcb, 1 ); FatPrepareWriteDirectoryFile( IrpContext, Vcb->RootDcb, ByteOffset, sizeof(DIRENT), &DirentBcb, &Dirent, FALSE, TRUE, &Status ); ASSERT( NT_SUCCESS( Status )); } else { // // Just mark this guy dirty now. // FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE ); } // // Now reconstruct the volume label dirent. // FatConstructLabelDirent( IrpContext, Dirent, &OemLabel ); // // Unpin the Bcb here so that we will get any IO errors // here before changing the VPB label. // FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinRepinnedBcbs( IrpContext ); // // Now set the upcased label in the VPB // RtlCopyMemory( &Vcb->Vpb->VolumeLabel[0], &UpcasedLabel.Buffer[0], UpcasedLabel.Length ); Vcb->Vpb->VolumeLabelLength = UpcasedLabel.Length; } else { // // Otherwise we're trying to delete the label // Locate the current volume label if there already is one // FatLocateVolumeLabel( IrpContext, Vcb, &Dirent, &DirentBcb, &ByteOffset ); // // Check that we really got one // if (Dirent == NULL) { try_return( Status = STATUS_SUCCESS ); } // // Now delete the current label. // Dirent->FileName[0] = FAT_DIRENT_DELETED; ASSERT( (Vcb->RootDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || RtlAreBitsSet( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap, ByteOffset / sizeof(DIRENT), 1 ) ); RtlClearBits( &Vcb->RootDcb->Specific.Dcb.FreeDirentBitmap, ByteOffset / sizeof(DIRENT), 1 ); FatSetDirtyBcb( IrpContext, DirentBcb, Vcb, TRUE ); // // Unpin the Bcb here so that we will get any IO errors // here before changing the VPB label. // FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinRepinnedBcbs( IrpContext ); // // Now set the label in the VPB // Vcb->Vpb->VolumeLabelLength = 0; } Status = STATUS_SUCCESS; FatSortDirectory(IrpContext, Vcb->RootDcb); try_exit: NOTHING; } finally { DebugUnwind( FatSetFsALabelInfo ); FatUnpinBcb( IrpContext, DirentBcb ); DebugTrace(-1, Dbg, "FatSetFsALabelInfo -> STATUS_SUCCESS\n", 0); } return Status; }
NTSTATUS SecondaryRecoverySession ( IN PSECONDARY Secondary ) { NTSTATUS status; LONG slotIndex; LARGE_INTEGER timeOut; OBJECT_ATTRIBUTES objectAttributes; ULONG reconnectionTry; PLIST_ENTRY ccblistEntry; BOOLEAN isLocalAddress; DebugTrace2( 0, Dbg2, ("SecondaryRecoverySession: Called Secondary = %p\n", Secondary) ); SetFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); ASSERT( FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ); ASSERT( Secondary->ThreadHandle ); ASSERT( IsListEmpty(&Secondary->RequestQueue) ); for (slotIndex=0; slotIndex < Secondary->Thread.SessionContext.SessionSlotCount; slotIndex++) { ASSERT( Secondary->Thread.SessionSlot[slotIndex] == NULL ); } if (Secondary->ThreadHandle) { ASSERT( Secondary->ThreadObject ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { NDASFAT_ASSERT( FALSE ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return status; } DebugTrace2( 0, Dbg2, ("Secondary_Stop: thread stoped\n") ); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = 0; Secondary->ThreadObject = 0; RtlZeroMemory( &Secondary->Thread.Flags, sizeof(SECONDARY) - FIELD_OFFSET(SECONDARY, Thread.Flags) ); } for (status = STATUS_UNSUCCESSFUL, reconnectionTry = 0; reconnectionTry < MAX_RECONNECTION_TRY; reconnectionTry++) { if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_LOCKED)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->NdasFatFlags, ND_FAT_DEVICE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY) { status = STATUS_SUCCESS; } else { status = ((PVOLUME_DEVICE_OBJECT) FatData.DiskFileSystemDeviceObject)-> NdfsCallback.SecondaryToPrimary( Secondary->VolDo->Vcb.Vpb->RealDevice, TRUE ); if (status == STATUS_NO_SUCH_DEVICE) { NDASFAT_ASSERT( FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_LOCKED) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } } //FatDebugTraceLevel = 0; DebugTrace2( 0, Dbg2, ("SecondaryToPrimary status = %x\n", status) ); #if 0 if (queryResult == TRUE) { BOOLEAN result0, result1; IRP_CONTEXT IrpContext; ASSERT( Secondary->VolDo->Vcb.VirtualVolumeFile ); result0 = CcPurgeCacheSection( &Secondary->VolDo->Vcb.SectionObjectPointers, NULL, 0, FALSE ); ASSERT( Secondary->VolDo->Vcb.RootDcb->Specific.Dcb.DirectoryFile ); result1 = CcPurgeCacheSection( &Secondary->VolDo->Vcb.RootDcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE ); ASSERT( result0 == TRUE ); ASSERT( result1 == TRUE ); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); SetFlag(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT); FatTearDownAllocationSupport ( &IrpContext, &Secondary->VolDo->Vcb ); FatSetupAllocationSupport( &IrpContext, &Secondary->VolDo->Vcb ); FatCheckDirtyBit( &IrpContext, &Secondary->VolDo->Vcb ); ASSERT( IrpContext.Repinned.Bcb[0] == NULL ); FatUnpinRepinnedBcbs( &IrpContext ); Secondary->VolDo->NetdiskEnableMode = NETDISK_SECONDARY2PRIMARY; Secondary->VolDo->SecondaryState = CONNECT_TO_LOCAL_STATE; } #endif if (status == STATUS_SUCCESS) { PVCB vcb = &Secondary->VolDo->Vcb; #if 0 TOP_LEVEL_CONTEXT topLevelContext; PTOP_LEVEL_CONTEXT threadTopLevelContext; #endif IRP_CONTEXT tempIrpContext2; PIRP_CONTEXT tempIrpContext = NULL; SetFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->SecondaryResource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->SecondaryResource) ); //FatReleaseAllResources( IrpContext ); //ObReferenceObject( vcb->TargetDeviceObject ); DebugTrace2( 0, Dbg2, ("Vcb->State = %X\n", vcb->VcbState) ); DebugTrace2( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); tempIrpContext = NULL; #if 0 threadTopLevelContext = FatInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); FatInitializeIrpContext( NULL, TRUE, &tempIrpContext ); FatUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); #endif tempIrpContext = &tempIrpContext2; RtlZeroMemory( tempIrpContext, sizeof(IRP_CONTEXT) ); SetFlag( tempIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); SetFlag( tempIrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); try { status = STATUS_UNSUCCESSFUL; status = CleanUpVcb( tempIrpContext, vcb ); } finally { //FatCompleteRequest( tempIrpContext, NULL, 0 ); //ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); ASSERT( status == STATUS_SUCCESS ); //ASSERT( FlagOn(vcb->VcbState, VCB_STATE_MOUNT_COMPLETED) ); ASSERT( FlagOn(Secondary->VolDo->NdasFatFlags, ND_FAT_DEVICE_FLAG_MOUNTED) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->SecondaryResource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->SecondaryResource) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); DebugTrace2( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->OpenFileCount) ); #if 0 tempIrpContext = NULL; threadTopLevelContext = FatInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); FatInitializeIrpContext( NULL, TRUE, &tempIrpContext ); FatUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); #endif Secondary->VolDo->NetdiskEnableMode = NETDISK_SECONDARY2PRIMARY; tempIrpContext = &tempIrpContext2; RtlZeroMemory( tempIrpContext, sizeof(IRP_CONTEXT) ); SetFlag( tempIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); SetFlag( tempIrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; SetFlag( Secondary->Flags, SECONDARY_FLAG_REMOUNT_VOLUME ); try { status = STATUS_UNSUCCESSFUL; status = NdasFatMountVolume( tempIrpContext, vcb->TargetDeviceObject, vcb->Vpb, NULL ); } finally { //FatCompleteRequest( tempIrpContext, NULL, 0 ); //ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } //ObDereferenceObject( vcb->TargetDeviceObject ); //FatDebugTraceLevel = 0xFFFFFFFFFFFFFFFF; //FatDebugTraceLevel |= DEBUG_TRACE_CREATE; ClearFlag( Secondary->Flags, SECONDARY_FLAG_REMOUNT_VOLUME ); ASSERT( status == STATUS_SUCCESS ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&FatData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); DebugTrace2( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace2( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->OpenFileCount) ); #if 0 if (vcb->MftScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->MftScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->MftScb->Header.Resource) ); } if (vcb->Mft2Scb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->Mft2Scb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->Mft2Scb->Header.Resource) ); } if (vcb->LogFileScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->LogFileScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->LogFileScb->Header.Resource) ); } if (vcb->VolumeDasdScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->VolumeDasdScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->VolumeDasdScb->Header.Resource) ); } if (vcb->AttributeDefTableScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->AttributeDefTableScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->AttributeDefTableScb->Header.Resource) ); } if (vcb->UpcaseTableScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->UpcaseTableScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->UpcaseTableScb->Header.Resource) ); } if (vcb->RootIndexScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->RootIndexScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->RootIndexScb->Header.Resource) ); } if (vcb->BitmapScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->BitmapScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->BitmapScb->Header.Resource) ); } if (vcb->BadClusterFileScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->BadClusterFileScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->BadClusterFileScb->Header.Resource) ); } if (vcb->MftBitmapScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->MftBitmapScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->MftBitmapScb->Header.Resource) ); } if (vcb->SecurityDescriptorStream) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityDescriptorStream->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityDescriptorStream->Header.Resource) ); } if (vcb->UsnJournal) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->UsnJournal->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->UsnJournal->Header.Resource) ); } if (vcb->ExtendDirectory) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->ExtendDirectory->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->ExtendDirectory->Header.Resource) ); } if (vcb->SecurityDescriptorHashIndex) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityDescriptorHashIndex->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityDescriptorHashIndex->Header.Resource) ); } if (vcb->SecurityIdIndex) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityIdIndex->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityIdIndex->Header.Resource) ); } #endif } status = ((PVOLUME_DEVICE_OBJECT) FatData.DiskFileSystemDeviceObject)-> NdfsCallback.QueryPrimaryAddress( &Secondary->VolDo->NetdiskPartitionInformation, &Secondary->PrimaryAddress, &isLocalAddress ); DebugTrace2( 0, Dbg2, ("RecoverSession: LfsTable_QueryPrimaryAddress status = %X\n", status) ); if (status == STATUS_SUCCESS && !(Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY && isLocalAddress)) { DebugTrace2( 0, Dbg, ("SecondaryRecoverySessionStart: Found PrimaryAddress :%02x:%02x:%02x:%02x:%02x:%02x/%d\n", Secondary->PrimaryAddress.Node[0], Secondary->PrimaryAddress.Node[1], Secondary->PrimaryAddress.Node[2], Secondary->PrimaryAddress.Node[3], Secondary->PrimaryAddress.Node[4], Secondary->PrimaryAddress.Node[5], NTOHS(Secondary->PrimaryAddress.Port)) ); } else { //ASSERT( FALSE ); continue; } KeInitializeEvent( &Secondary->ReadyEvent, NotificationEvent, FALSE ); KeInitializeEvent( &Secondary->RequestEvent, NotificationEvent, FALSE ); InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); status = PsCreateSystemThread( &Secondary->ThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, SecondaryThreadProc, Secondary ); if (!NT_SUCCESS(status)) { ASSERT( NDASFAT_UNEXPECTED ); break; } status = ObReferenceObjectByHandle( Secondary->ThreadHandle, FILE_READ_DATA, NULL, KernelMode, &Secondary->ThreadObject, NULL ); if (!NT_SUCCESS(status)) { ASSERT (NDASFAT_INSUFFICIENT_RESOURCES ); break; } timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &Secondary->ReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); break; } KeClearEvent( &Secondary->ReadyEvent ); InterlockedIncrement( &Secondary->SessionId ); ExAcquireFastMutex( &Secondary->FastMutex ); if (!FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_START) || FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_STOPED)) { ExReleaseFastMutex( &Secondary->FastMutex ); if (Secondary->Thread.SessionStatus == STATUS_DISK_CORRUPT_ERROR) { status = STATUS_SUCCESS; break; } timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); return status; } DebugTrace2( 0, Dbg, ("Secondary_Stop: thread stoped\n") ); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = 0; Secondary->ThreadObject = 0; RtlZeroMemory( &Secondary->Thread.Flags, sizeof(SECONDARY) - FIELD_OFFSET(SECONDARY, Thread.Flags) ); continue; } ExReleaseFastMutex( &Secondary->FastMutex ); status = STATUS_SUCCESS; DebugTrace2( 0, Dbg2, ("SecondaryRecoverySession Success Secondary = %p\n", Secondary) ); break; }
NTSTATUS FatCommonSetVolumeInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for setting Volume Information called by both the fsd and fsp threads. Arguments: Irp - Supplies the Irp being processed Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PVCB Vcb; PFCB Fcb; PCCB Ccb; TYPE_OF_OPEN TypeOfOpen; ULONG Length; FS_INFORMATION_CLASS FsInformationClass; PVOID Buffer; // // Get the current stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonSetVolumeInfo...\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp ); DebugTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.SetVolume.Length); DebugTrace( 0, Dbg, "->FsInformationClass = %08lx\n", IrpSp->Parameters.SetVolume.FsInformationClass); DebugTrace( 0, Dbg, "->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer); // // Reference our input parameters to make things easier // Length = IrpSp->Parameters.SetVolume.Length; FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass; Buffer = Irp->AssociatedIrp.SystemBuffer; // // Decode the file object to get the Vcb // TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); if (TypeOfOpen != UserVolumeOpen) { FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> STATUS_ACCESS_DENIED\n", 0); return STATUS_ACCESS_DENIED; } // // Acquire exclusive access to the Vcb and enqueue the Irp if we didn't // get access // if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) { DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0); Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status ); return Status; } try { // // Make sure the vcb is in a usable condition. This will raise // and error condition if the volume is unusable // // Also verify the Root Dcb since we need info from there. // FatVerifyFcb( IrpContext, Vcb->RootDcb ); // // Based on the information class we'll do different actions. Each // of the procedures that we're calling performs the action if // possible and returns true if it successful and false if it couldn't // wait for any I/O to complete. // switch (FsInformationClass) { case FileFsLabelInformation: Status = FatSetFsLabelInfo( IrpContext, Vcb, Buffer ); break; default: Status = STATUS_INVALID_PARAMETER; break; } FatUnpinRepinnedBcbs( IrpContext ); } finally { DebugUnwind( FatCommonSetVolumeInfo ); FatReleaseVcb( IrpContext, Vcb ); if (!AbnormalTermination()) { FatCompleteRequest( IrpContext, Irp, Status ); } DebugTrace(-1, Dbg, "FatCommonSetVolumeInfo -> %08lx\n", Status); } return Status; }