static NTSTATUS NdasNtfsSecondaryUserFsRequest ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS Status = STATUS_SUCCESS; ULONG FsControlCode; ULONG FsControlCodeFunction; PIO_STACK_LOCATION IrpSp; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PSCB scb; PCCB ccb; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; _U8 *ndfsWinxpRequestData; LARGE_INTEGER timeOut; struct FileSystemControl fileSystemControl; PVOID inputBuffer = NULL; ULONG inputBufferLength; PVOID outputBuffer = NULL; ULONG outputBufferLength; ULONG bufferLength; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_IRP( Irp ); PAGED_CODE(); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); IrpSp = IoGetCurrentIrpStackLocation( Irp ); FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; FsControlCodeFunction = (FsControlCode & 0x00003FFC) >> 2; DebugTrace( +1, Dbg, ("NtfsUserFsRequest, FsControlCode = %08lx, FsControlCodeFunction = %d\n", FsControlCode, FsControlCodeFunction) ); switch ( FsControlCode ) { case FSCTL_REQUEST_OPLOCK_LEVEL_1: case FSCTL_REQUEST_OPLOCK_LEVEL_2: case FSCTL_REQUEST_BATCH_OPLOCK: case FSCTL_REQUEST_FILTER_OPLOCK: case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: case FSCTL_OPLOCK_BREAK_NOTIFY: case FSCTL_OPBATCH_ACK_CLOSE_PENDING : case FSCTL_OPLOCK_BREAK_ACK_NO_2: ASSERT( FALSE ); //Status = NtfsOplockRequest( IrpContext, Irp ); break; case FSCTL_LOCK_VOLUME: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsLockVolume( IrpContext, Irp ); break; case FSCTL_UNLOCK_VOLUME: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsUnlockVolume( IrpContext, Irp ); break; case FSCTL_DISMOUNT_VOLUME: { #if 0 NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; #else BOOLEAN secondaryCreateResourceAcquired = FALSE; ASSERT( IS_WINDOWSVISTA_OR_LATER() ); do { BOOLEAN secondaryRecoveryResourceAcquired; DebugTrace( 0, Dbg, ("%s: IRP_MN_QUERY_REMOVE_DEVICE volDo = %p, NetdiskEnableMode = %d\n", __FUNCTION__, volDo, volDo->NetdiskEnableMode) ); secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->RecoveryResource, FALSE ); if (secondaryRecoveryResourceAcquired == FALSE) { Status = STATUS_ACCESS_DENIED; break; } SecondaryReleaseResourceLite( IrpContext, &volDo->RecoveryResource ); ExAcquireFastMutex( &volDo->Secondary->FastMutex ); if (!volDo->Secondary->TryCloseActive) { volDo->Secondary->TryCloseActive = TRUE; ExReleaseFastMutex( &volDo->Secondary->FastMutex ); Secondary_Reference( volDo->Secondary ); //NtfsDebugTraceLevel |= DEBUG_TRACE_CLOSE; SecondaryTryClose( &IrpContext, volDo->Secondary ); //NtfsDebugTraceLevel &= ~DEBUG_TRACE_CLOSE; } else { ExReleaseFastMutex( &volDo->Secondary->FastMutex ); } if (volDo->Vcb.SecondaryCloseCount) { LARGE_INTEGER interval; // Wait all files closed interval.QuadPart = (-1 * HZ); //delay 1 seconds KeDelayExecutionThread(KernelMode, FALSE, &interval); } CcWaitForCurrentLazyWriterActivity(); secondaryCreateResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->CreateResource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); if (secondaryCreateResourceAcquired == FALSE) { Status = STATUS_ACCESS_DENIED; break; } if (volDo->Vcb.SecondaryCloseCount) { LONG ccbCount; PLIST_ENTRY ccbListEntry; PVOID restartKey; PFCB fcb; ExAcquireFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); for (ccbCount = 0, ccbListEntry = volDo->Secondary->RecoveryCcbQueue.Flink; ccbListEntry != &volDo->Secondary->RecoveryCcbQueue; ccbListEntry = ccbListEntry->Flink, ccbCount++); ExReleaseFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); ASSERT( !IsListEmpty(&volDo->Secondary->RecoveryCcbQueue) ); ASSERT( ccbCount == volDo->Vcb.SecondaryCloseCount ); DebugTrace( 0, Dbg, ("IRP_MN_QUERY_REMOVE_DEVICE: Vcb->SecondaryCloseCount = %d, Vcb->SecondaryCleanupCount = %d, Vcb->CloseCount = %d, ccbCount = %d\n", volDo->Vcb.SecondaryCloseCount, volDo->Vcb.SecondaryCleanupCount, volDo->Vcb.CloseCount, ccbCount) ); restartKey = NULL; fcb = NdasNtfsGetNextFcbTableEntry( &volDo->Vcb, &restartKey ); ASSERT( fcb != NULL || !IsListEmpty(&volDo->Secondary->DeletedFcbQueue) ); Status = STATUS_ACCESS_DENIED; break; } else { Status = STATUS_SUCCESS; SetFlag( volDo->Secondary->Flags, SECONDARY_FLAG_DISMOUNTING ); } } while(0); if (Status != STATUS_SUCCESS) { if (secondaryCreateResourceAcquired) { SecondaryReleaseResourceLite( IrpContext, &volDo->CreateResource ); secondaryCreateResourceAcquired = FALSE; } NtfsCompleteRequest( IrpContext, Irp, Status ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; } Status = NtfsDismountVolume( IrpContext, Irp ); SecondaryReleaseResourceLite( IrpContext, &volDo->CreateResource ); return Status; #endif break; } case FSCTL_IS_VOLUME_MOUNTED: Status = NtfsIsVolumeMounted( IrpContext, Irp ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_MARK_VOLUME_DIRTY: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsDirtyVolume( IrpContext, Irp ); break; case FSCTL_IS_PATHNAME_VALID: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_SUCCESS ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_QUERY_RETRIEVAL_POINTERS: Status = NtfsQueryRetrievalPointers( IrpContext, Irp ); break; case FSCTL_GET_COMPRESSION: //NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST ); //DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); //return Status; Status = NtfsGetCompression( IrpContext, Irp ); break; case FSCTL_SET_COMPRESSION: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; Status = NtfsSetCompression( IrpContext, Irp ); break; case FSCTL_MARK_AS_SYSTEM_HIVE: Status = NtfsMarkAsSystemHive( IrpContext, Irp ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_FILESYSTEM_GET_STATISTICS: Status = NtfsGetStatistics( IrpContext, Irp ); break; case FSCTL_GET_NTFS_VOLUME_DATA: Status = NtfsGetVolumeData( IrpContext, Irp ); break; case FSCTL_GET_VOLUME_BITMAP: Status = NtfsGetVolumeBitmap( IrpContext, Irp ); break; case FSCTL_GET_RETRIEVAL_POINTERS: Status = NtfsGetRetrievalPointers( IrpContext, Irp ); break; case FSCTL_GET_NTFS_FILE_RECORD: Status = NtfsGetMftRecord( IrpContext, Irp ); break; case FSCTL_MOVE_FILE: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; Status = NtfsDefragFile( IrpContext, Irp ); if (Status == STATUS_SUCCESS) { PMOVE_FILE_DATA moveFileData = IrpContext->InputBuffer; PFILE_OBJECT moveFileObject; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if (Status != STATUS_SUCCESS) { break; } ObDereferenceObject( moveFileObject ); if (!IS_SECONDARY_FILEOBJECT(moveFileObject)) { ASSERT( FALSE ); Status = STATUS_INVALID_PARAMETER; } } if (Status != STATUS_SUCCESS) DebugTrace( 0, Dbg2, ("NtfsDefragFile: status = %x\n", Status) ); break; case FSCTL_IS_VOLUME_DIRTY: Status = NtfsIsVolumeDirty( IrpContext, Irp ); break; case FSCTL_ALLOW_EXTENDED_DASD_IO: Status = NtfsSetExtendedDasdIo( IrpContext, Irp ); break; case FSCTL_SET_REPARSE_POINT: Status = NtfsSetReparsePoint( IrpContext, Irp ); break; case FSCTL_GET_REPARSE_POINT: Status = NtfsGetReparsePoint( IrpContext, Irp ); break; case FSCTL_DELETE_REPARSE_POINT: Status = NtfsDeleteReparsePoint( IrpContext, Irp ); break; case FSCTL_SET_OBJECT_ID: Status = NtfsSetObjectId( IrpContext, Irp ); // In ObjIdSup.c break; case FSCTL_GET_OBJECT_ID: Status = NtfsGetObjectId( IrpContext, Irp ); // In ObjIdSup.c break; case FSCTL_DELETE_OBJECT_ID: Status = NtfsDeleteObjectId( IrpContext, Irp ); // In ObjIdSup.c break; case FSCTL_SET_OBJECT_ID_EXTENDED: Status = NtfsSetObjectIdExtendedInfo( IrpContext, Irp ); // In ObjIdSup.c break; case FSCTL_CREATE_OR_GET_OBJECT_ID: Status = NtfsCreateOrGetObjectId( IrpContext, Irp ); if (IrpSp->Parameters.FileSystemControl.InputBufferLength) IrpContext->InputBuffer = Irp->AssociatedIrp.SystemBuffer; else IrpContext->InputBuffer = NULL; break; case FSCTL_READ_USN_JOURNAL: Status = NtfsReadUsnJournal( IrpContext, Irp, TRUE ); // In UsnSup.c break; case FSCTL_CREATE_USN_JOURNAL: Status = NtfsCreateUsnJournal( IrpContext, Irp ); break; case FSCTL_ENUM_USN_DATA: Status = NtfsReadFileRecordUsnData( IrpContext, Irp ); break; case FSCTL_READ_FILE_USN_DATA: Status = NtfsReadFileUsnData( IrpContext, Irp ); break; case FSCTL_WRITE_USN_CLOSE_RECORD: Status = NtfsWriteUsnCloseRecord( IrpContext, Irp ); break; case FSCTL_QUERY_USN_JOURNAL: Status = NtfsQueryUsnJournal( IrpContext, Irp ); break; case FSCTL_DELETE_USN_JOURNAL: Status = NtfsDeleteUsnJournal( IrpContext, Irp ); break; case FSCTL_MARK_HANDLE: Status = NtfsMarkHandle( IrpContext, Irp ); if (Status == STATUS_SUCCESS) { PMARK_HANDLE_INFO markHandleInfo = inputBuffer; PFILE_OBJECT volumeFileObject; Status = ObReferenceObjectByHandle( markHandleInfo->VolumeHandle, FILE_READ_DATA, 0, KernelMode, &volumeFileObject, NULL ); if (Status != STATUS_SUCCESS) { break; } ObDereferenceObject( volumeFileObject ); if (!IS_SECONDARY_FILEOBJECT(volumeFileObject)) { Status = STATUS_INVALID_PARAMETER; } } break; case FSCTL_SECURITY_ID_CHECK: Status = NtfsBulkSecurityIdCheck( IrpContext, Irp ); break; case FSCTL_FIND_FILES_BY_SID: Status = NtfsFindFilesOwnedBySid( IrpContext, Irp ); break; case FSCTL_SET_SPARSE : NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsSetSparse( IrpContext, Irp ); break; case FSCTL_SET_ZERO_DATA : NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; Status = NtfsZeroRange( IrpContext, Irp ); break; case FSCTL_QUERY_ALLOCATED_RANGES : Status = NtfsQueryAllocatedRanges( IrpContext, Irp ); break; case FSCTL_ENCRYPTION_FSCTL_IO : NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsEncryptionFsctl( IrpContext, Irp ); break; case FSCTL_SET_ENCRYPTION : NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsSetEncryption( IrpContext, Irp ); break; case FSCTL_READ_RAW_ENCRYPTED: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsReadRawEncrypted( IrpContext, Irp ); break; case FSCTL_WRITE_RAW_ENCRYPTED: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsWriteRawEncrypted( IrpContext, Irp ); break; case FSCTL_EXTEND_VOLUME: NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = NtfsExtendVolume( IrpContext, Irp ); break; case FSCTL_READ_FROM_PLEX: Status = NtfsReadFromPlex( IrpContext, Irp ); DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_FILE_PREFETCH: Status = NtfsPrefetchFile( IrpContext, Irp ); break; default : DebugTrace( 0, DEBUG_TRACE_ALL, ("NtfsUserFsRequest: Invalid control code FsControlCode = %08lx, FsControlCodeFunction = %d\n", FsControlCode, FsControlCodeFunction) ); NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST ); break; } ASSERT( !ExIsResourceAcquiredSharedLite(&volDo->Vcb.Resource) ); if (Status != STATUS_SUCCESS) { DebugTrace( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; } if (IrpSp->Parameters.FileSystemControl.InputBufferLength >= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize || IrpSp->Parameters.FileSystemControl.OutputBufferLength >= volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize) { ASSERT( FALSE ); NtfsCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_DEVICE_REQUEST ); return Status; } inputBuffer = IrpContext->InputBuffer; outputBuffer = IrpContext->outputBuffer; ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength ? (inputBuffer != NULL) : (inputBuffer == NULL) ); ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength ? (outputBuffer != NULL) : (outputBuffer == NULL) ); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); if (!FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT)) { return NtfsPostRequest( IrpContext, Irp ); } try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->SessionResource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); } ASSERT( IS_SECONDARY_FILEOBJECT(IrpSp->FileObject) ); typeOfOpen = NtfsDecodeFileObject( IrpContext, IrpSp->FileObject, &vcb, &fcb, &scb, &ccb, TRUE ); if (FlagOn(ccb->NdasNtfsFlags, ND_NTFS_CCB_FLAG_UNOPENED)) { ASSERT( FlagOn(ccb->NdasNtfsFlags, ND_NTFS_CCB_FLAG_CORRUPTED) ); try_return( Status = STATUS_FILE_CORRUPT_ERROR ); } fileSystemControl.FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; fileSystemControl.InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; fileSystemControl.OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; if (inputBuffer == NULL) fileSystemControl.InputBufferLength = 0; if (outputBuffer == NULL) fileSystemControl.OutputBufferLength = 0; outputBufferLength = fileSystemControl.OutputBufferLength; if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 inputBufferLength = 0; } else if(fileSystemControl.FsControlCode == FSCTL_MARK_HANDLE) { // 63 inputBufferLength = 0; } else { inputBufferLength = fileSystemControl.InputBufferLength; } bufferLength = (inputBufferLength >= outputBufferLength) ? inputBufferLength : outputBufferLength; secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_FILE_SYSTEM_CONTROL, bufferLength ); if (secondaryRequest == NULL) { Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; try_return( Status ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FILE_SYSTEM_CONTROL, inputBufferLength ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, Irp, IrpSp, ccb->PrimaryFileHandle ); ndfsWinxpRequestHeader->FileSystemControl.OutputBufferLength = fileSystemControl.OutputBufferLength; ndfsWinxpRequestHeader->FileSystemControl.InputBufferLength = fileSystemControl.InputBufferLength; ndfsWinxpRequestHeader->FileSystemControl.FsControlCode = fileSystemControl.FsControlCode; if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 PMOVE_FILE_DATA moveFileData = inputBuffer; PFILE_OBJECT moveFileObject; PCCB moveCcb; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if (Status != STATUS_SUCCESS) { ASSERT( FALSE ); try_return( Status ); } ObDereferenceObject( moveFileObject ); moveCcb = moveFileObject->FsContext2; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.FileHandle = moveCcb->PrimaryFileHandle; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.StartingVcn = moveFileData->StartingVcn.QuadPart; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.StartingLcn = moveFileData->StartingLcn.QuadPart; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.ClusterCount = moveFileData->ClusterCount; } else if(fileSystemControl.FsControlCode == FSCTL_MARK_HANDLE) { // 63 PMARK_HANDLE_INFO markHandleInfo = inputBuffer; PFILE_OBJECT volumeFileObject; PCCB volumeCcb; Status = ObReferenceObjectByHandle( markHandleInfo->VolumeHandle, FILE_READ_DATA, 0, KernelMode, &volumeFileObject, NULL ); if (Status != STATUS_SUCCESS) { try_return( Status ); } ObDereferenceObject( volumeFileObject ); volumeCcb = volumeFileObject->FsContext2; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.UsnSourceInfo = markHandleInfo->UsnSourceInfo; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.VolumeHandle = volumeCcb->PrimaryFileHandle; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.HandleInfo = markHandleInfo->HandleInfo; } else { ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1); if(inputBufferLength) RtlCopyMemory( ndfsWinxpRequestData, inputBuffer, inputBufferLength ); } ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASNTFS_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if(Status != STATUS_SUCCESS) { secondaryRequest = NULL; try_return( Status = STATUS_IO_DEVICE_ERROR ); } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; Status = Irp->IoStatus.Status = ndfsWinxpReplytHeader->Status; Irp->IoStatus.Information = ndfsWinxpReplytHeader->Information; if (FsControlCode == FSCTL_GET_NTFS_VOLUME_DATA && Status != STATUS_SUCCESS) DebugTrace( 0, Dbg2, ("FSCTL_GET_NTFS_VOLUME_DATA: Status = %x, Irp->IoStatus.Information = %d\n", Status, Irp->IoStatus.Information) ); if (secondaryRequest->NdfsReplyHeader.MessageSize - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REPLY_HEADER)) { ASSERT( Irp->IoStatus.Status == STATUS_SUCCESS || Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ); ASSERT( Irp->IoStatus.Information ); ASSERT( Irp->IoStatus.Information <= outputBufferLength ); ASSERT( outputBuffer ); RtlCopyMemory( outputBuffer, (_U8 *)(ndfsWinxpReplytHeader+1), Irp->IoStatus.Information ); } if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE && Status != STATUS_SUCCESS) DebugTrace( 0, Dbg2, ("NtfsDefragFile: status = %x\n", Status) ); if (Status == STATUS_SUCCESS && fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 PMOVE_FILE_DATA moveFileData = inputBuffer; PFILE_OBJECT moveFileObject; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB moveFcb; PSCB moveScb; PCCB moveCcb; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if(Status != STATUS_SUCCESS) { try_return( Status ); } ObDereferenceObject( moveFileObject ); typeOfOpen = NtfsDecodeFileObject( IrpContext, moveFileObject, &vcb, &moveFcb, &moveScb, &moveCcb, TRUE ); if (typeOfOpen == UserFileOpen && ndfsWinxpReplytHeader->FileInformationSet && ndfsWinxpReplytHeader->AllocationSize) { PNDFS_NTFS_MCB_ENTRY mcbEntry; ULONG index; VCN testVcn; SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ); NtfsAcquireFcbWithPaging( IrpContext, moveFcb, 0 ); NtfsAcquireNtfsMcbMutex( &moveScb->Mcb ); mcbEntry = (PNDFS_NTFS_MCB_ENTRY)( ndfsWinxpReplytHeader+1 ); if (moveScb->Header.AllocationSize.QuadPart) { NtfsRemoveNtfsMcbEntry( &moveScb->Mcb, 0, 0xFFFFFFFF ); } for (index=0, testVcn=0; index < ndfsWinxpReplytHeader->NumberOfMcbEntry; index++) { ASSERT( mcbEntry[index].Vcn == testVcn ); testVcn += (LONGLONG)mcbEntry[index].ClusterCount; NtfsAddNtfsMcbEntry( &moveScb->Mcb, mcbEntry[index].Vcn, mcbEntry[index].Lcn, (LONGLONG)mcbEntry[index].ClusterCount, TRUE ); } ASSERT( LlBytesFromClusters(vcb, testVcn) == ndfsWinxpReplytHeader->AllocationSize ); if (moveScb->Header.AllocationSize.QuadPart != ndfsWinxpReplytHeader->AllocationSize) SetFlag( moveScb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE ); moveScb->Header.FileSize.QuadPart = ndfsWinxpReplytHeader->FileSize; moveScb->Header.AllocationSize.QuadPart = ndfsWinxpReplytHeader->AllocationSize; ASSERT( moveScb->Header.AllocationSize.QuadPart >= moveScb->Header.FileSize.QuadPart ); if (moveFileObject->SectionObjectPointer->DataSectionObject != NULL && moveFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( moveFileObject, (PCC_FILE_SIZES)&moveScb->Header.AllocationSize, FALSE, &NtfsData.CacheManagerCallbacks, moveScb ); } if (CcIsFileCached(moveFileObject)) { NtfsSetBothCacheSizes( moveFileObject, (PCC_FILE_SIZES)&scb->Header.AllocationSize, moveScb ); } NtfsReleaseNtfsMcbMutex( &moveScb->Mcb ); NtfsReleaseFcb( IrpContext, moveFcb ); } } try_exit: NOTHING; } finally { if (secondarySessionResourceAcquired == TRUE) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } NtfsCompleteRequest( IrpContext, Irp, Status ); return Status; }
NTSTATUS SecondaryRecoverySession ( IN PSECONDARY Secondary ) { NTSTATUS status; LONG slotIndex; LARGE_INTEGER timeOut; OBJECT_ATTRIBUTES objectAttributes; ULONG reconnectionTry; PLIST_ENTRY ccblistEntry; BOOLEAN isLocalAddress; 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 = -NDASNTFS_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if(status != STATUS_SUCCESS) { ASSERT( NDASNTFS_BUG ); return status; } DebugTrace( 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_TARGET_DEVICE_STOPPED)) { 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->NdasNtfsFlags, NDAS_NTFS_DEVICE_FLAG_SHUTDOWN)) { //DebugTrace( 0, Dbg2, ("SecondaryToPrimary NDAS_NTFS_DEVICE_FLAG_SHUTDOWN\n") ); //DbgPrint( "SecondaryToPrimary NDAS_NTFS_DEVICE_FLAG_SHUTDOWN\n" ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY) { status = STATUS_SUCCESS; } else { status = ((PVOLUME_DEVICE_OBJECT) NdasNtfsFileSystemDeviceObject)-> NdfsCallback.SecondaryToPrimary( Secondary->VolDo->Vcb.Vpb->RealDevice, TRUE ); if (status == STATUS_NO_SUCH_DEVICE) { NDAS_ASSERT( FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_TARGET_DEVICE_STOPPED) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } } //NtfsDebugTraceLevel = 0; DebugTrace( 0, Dbg2, ("SecondaryToPrimary status = %x\n", status) ); if (status == STATUS_SUCCESS) { PVCB vcb = &Secondary->VolDo->Vcb; TOP_LEVEL_CONTEXT topLevelContext; PTOP_LEVEL_CONTEXT threadTopLevelContext; PIRP_CONTEXT tempIrpContext = NULL; SetFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); DebugTrace( 0, Dbg2, ("Vcb->State = %X\n", vcb->VcbState) ); DebugTrace( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); tempIrpContext = NULL; threadTopLevelContext = NtfsInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); NtfsInitializeIrpContext( NULL, TRUE, &tempIrpContext ); NtfsUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); SetFlag( tempIrpContext->NdasNtfsFlags, NDAS_NTFS_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; try { status = CleanUpVcb( tempIrpContext, vcb ); } finally { NtfsCompleteRequest( tempIrpContext, NULL, 0 ); ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } ASSERT( status == STATUS_SUCCESS ); ASSERT( FlagOn(vcb->VcbState, VCB_STATE_MOUNT_COMPLETED) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); DebugTrace( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->CloseCount) ); Secondary->VolDo->NetdiskEnableMode = NETDISK_SECONDARY2PRIMARY; tempIrpContext = NULL; threadTopLevelContext = NtfsInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); NtfsInitializeIrpContext( NULL, TRUE, &tempIrpContext ); NtfsUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); //tempIrpContext->TopLevelIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; //tempIrpContext->TopLevelIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; try { status = NdasNtfsMountVolume( tempIrpContext, vcb ); } finally { NtfsCompleteRequest( tempIrpContext, NULL, 0 ); ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } NDAS_ASSERT( status == STATUS_SUCCESS ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); DebugTrace( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->CloseCount) ); 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) ); } } Secondary->NumberOfPrimaryAddress = 0; status = ((PVOLUME_DEVICE_OBJECT) NdasNtfsFileSystemDeviceObject)-> NdfsCallback.QueryPrimaryAddress( &Secondary->VolDo->NetdiskPartitionInformation, Secondary->PrimaryAddressList, &Secondary->NumberOfPrimaryAddress, &isLocalAddress ); DebugTrace2( 0, Dbg2, ("RecoverySession: QueryPrimaryAddress status = %X\n", status) ); if (status == STATUS_SUCCESS && !(Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY && isLocalAddress)) { LONG i; NDAS_ASSERT( Secondary->NumberOfPrimaryAddress ); for (i = 0; i < Secondary->NumberOfPrimaryAddress; i++) { DebugTrace2( 0, Dbg, ("RecoverySession: Secondary = %p Found PrimaryAddress[%d] :%02x:%02x:%02x:%02x:%02x:%02x/%d\n", Secondary, i, Secondary->PrimaryAddressList[i].Node[0], Secondary->PrimaryAddressList[i].Node[1], Secondary->PrimaryAddressList[i].Node[2], Secondary->PrimaryAddressList[i].Node[3], Secondary->PrimaryAddressList[i].Node[4], Secondary->PrimaryAddressList[i].Node[5], NTOHS(Secondary->PrimaryAddressList[i].Port)) ); } } else { 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( NDASNTFS_UNEXPECTED ); break; } status = ObReferenceObjectByHandle( Secondary->ThreadHandle, FILE_READ_DATA, NULL, KernelMode, &Secondary->ThreadObject, NULL ); if (!NT_SUCCESS(status)) { ASSERT( NDASNTFS_INSUFFICIENT_RESOURCES ); break; } timeOut.QuadPart = -NDASNTFS_TIME_OUT; status = KeWaitForSingleObject( &Secondary->ReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if(status != STATUS_SUCCESS) { ASSERT( NDASNTFS_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 = -NDASNTFS_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if(status != STATUS_SUCCESS) { ASSERT( NDASNTFS_BUG ); return status; } DebugTrace( 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; DebugTrace( 0, Dbg2, ("SessionRecovery Success Secondary = %p\n", Secondary) ); break; }
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 NtfsFsdPnp ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD entry point for plug and play (Pnp). Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status = STATUS_SUCCESS; TOP_LEVEL_CONTEXT TopLevelContext; PTOP_LEVEL_CONTEXT ThreadTopLevelContext; PIRP_CONTEXT IrpContext = NULL; #if __NDAS_NTFS__ if ((PVOID)NdasNtfsControlDeviceObject == VolumeDeviceObject) { Status = Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return Status; } #endif ASSERT_IRP( Irp ); UNREFERENCED_PARAMETER( VolumeDeviceObject ); #ifdef NTFSPNPDBG if (NtfsDebugTraceLevel != 0) SetFlag( NtfsDebugTraceLevel, DEBUG_TRACE_PNP ); #endif DebugTrace( +1, Dbg, ("NtfsFsdPnp\n") ); // // Call the common Pnp routine // FsRtlEnterFileSystem(); switch( IoGetCurrentIrpStackLocation( Irp )->MinorFunction ) { case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_REMOVE_DEVICE: case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_SURPRISE_REMOVAL: ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE ); break; default: ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, TRUE ); break; } do { try { // // We are either initiating this request or retrying it. // if (IrpContext == NULL) { // // Allocate and initialize the Irp. // NtfsInitializeIrpContext( Irp, TRUE, &IrpContext ); // // Initialize the thread top level structure, if needed. // NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext ); } else if (Status == STATUS_LOG_FILE_FULL) { NtfsCheckpointForLogFileFull( IrpContext ); } #if __NDAS_NTFS_SECONDARY__ if (!FlagOn(VolumeDeviceObject->NetdiskPartitionInformation.Flags, NETDISK_PARTITION_INFORMATION_FLAG_INDIRECT) && VolumeDeviceObject->NetdiskEnableMode == NETDISK_SECONDARY) { if ((IrpContext->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE || IrpContext->MinorFunction == IRP_MN_SURPRISE_REMOVAL || IrpContext->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE)) { BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( NtfsIsTopLevelRequest(IrpContext) ); Status = STATUS_SUCCESS; for (;;) { NDAS_ASSERT( secondaryRecoveryResourceAcquired == FALSE ); NDAS_ASSERT( secondaryResourceAcquired == FALSE ); if (!FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT)) { Status = NtfsPostRequest( IrpContext, Irp ); break; } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->RecoveryResource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); try { SecondaryRecoverySessionStart( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); NDAS_ASSERT( secondaryResourceAcquired == TRUE ); break; } if (Status == STATUS_SUCCESS) { try { if (VolumeDeviceObject->NetdiskEnableMode != NETDISK_SECONDARY) { NDAS_ASSERT( VolumeDeviceObject->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY ); NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); } SetFlag( IrpContext->NdasNtfsFlags, NDAS_NTFS_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); Status = NtfsCommonPnp( IrpContext, &Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Resource ); } } } else { if (VolumeDeviceObject->NetdiskEnableMode != NETDISK_SECONDARY) { NDAS_ASSERT( VolumeDeviceObject->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY ); NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); } SetFlag( IrpContext->NdasNtfsFlags, NDAS_NTFS_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); Status = NtfsCommonPnp( IrpContext, &Irp ); } } else { Status = NtfsCommonPnp( IrpContext, &Irp ); } #else Status = NtfsCommonPnp( IrpContext, &Irp ); #endif break; } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
NTSTATUS FatFsdCleanup ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of closing down a handle to a file object. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being Cleanup exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel; PAGED_CODE(); #if __NDAS_FAT__ if ((PVOID)FatControlDeviceObject == VolumeDeviceObject) { Status = Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return Status; } #endif // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS // if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } DebugTrace(+1, Dbg, "FatFsdCleanup\n", 0); // // Call the common Cleanup routine, with blocking allowed. // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); #if (__NDAS_FAT_PRIMARY__ || __NDAS_FAT_SECONDARY__) do { try { if (IrpContext == NULL) { IrpContext = FatCreateIrpContext( Irp, TRUE ); IrpContext->TopLevel = TopLevel; #if __NDAS_FAT_PRIMARY__ { ULONG_PTR stackBottom; ULONG_PTR stackTop; BOOLEAN validPrimaryRequest = FALSE; PPRIMARY_REQUEST_INFO primaryRequestInfo; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); primaryRequestInfo = (PPRIMARY_REQUEST_INFO)IoGetTopLevelIrp(); IoGetStackLimits( &stackTop, &stackBottom ); if ( (ULONG_PTR)primaryRequestInfo <= stackBottom - sizeof(PRIMARY_REQUEST_INFO) && (ULONG_PTR) primaryRequestInfo >= stackTop && (!FlagOn( (ULONG_PTR) primaryRequestInfo, 0x3 )) && primaryRequestInfo->PrimaryTag == 0xe2027482) { validPrimaryRequest = TRUE; } if (validPrimaryRequest) { //ASSERT( FatIsTopLevelRequest(IrpContext) ); IoSetTopLevelIrp( NULL ); TopLevel = FatIsIrpTopLevel( Irp ); ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL ); if (IsListEmpty(&VolumeDeviceObject->PrimarySessionQueue)) { NDAS_ASSERT( FALSE ); } IrpContext->PrimaryRequestInfo = *primaryRequestInfo; DebugTrace2( 0, Dbg, ("primaryRequestInfo = %p\n", primaryRequestInfo) ); } } #endif } #if __NDAS_FAT_SECONDARY__ if (IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( FatIsTopLevelRequest(IrpContext) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); Status = STATUS_SUCCESS; while (TRUE) { ASSERT( secondaryRecoveryResourceAcquired == FALSE ); ASSERT( secondaryResourceAcquired == FALSE ); if (FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->RecoveryResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); try { SecondaryRecoverySessionStart( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (secondaryResourceAcquired == FALSE) { ASSERT( FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING) ); continue; } break; } if (Status == STATUS_SUCCESS) { try { Status = FatCommonCleanup( IrpContext, Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Resource ); } } } else Status = FatCommonCleanup( IrpContext, Irp ); #else Status = FatCommonCleanup( IrpContext, Irp ); #endif } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT);
NTSTATUS NtfsFsdLockControl ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of Lock Control. Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { TOP_LEVEL_CONTEXT TopLevelContext; PTOP_LEVEL_CONTEXT ThreadTopLevelContext; NTSTATUS Status = STATUS_SUCCESS; PIRP_CONTEXT IrpContext = NULL; #if __NDAS_NTFS__ if ((PVOID)NdasNtfsControlDeviceObject == VolumeDeviceObject) { Status = Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return Status; } #endif ASSERT_IRP( Irp ); UNREFERENCED_PARAMETER( VolumeDeviceObject ); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsFsdLockControl\n") ); // // Call the common Lock Control routine // FsRtlEnterFileSystem(); ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE ); do { try { // // We are either initiating this request or retrying it. // if (IrpContext == NULL) { // // Allocate and initialize the Irp. // NtfsInitializeIrpContext( Irp, CanFsdWait( Irp ), &IrpContext ); // // Initialize the thread top level structure, if needed. // NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext ); } else if (Status == STATUS_LOG_FILE_FULL) { NtfsCheckpointForLogFileFull( IrpContext ); } #if __NDAS_NTFS_SECONDARY__ if (IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( NtfsIsTopLevelRequest(IrpContext) ); SetFlag( IrpContext->NdasNtfsFlags, NDAS_NTFS_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); SetFlag( IrpContext->NdasNtfsFlags, NDAS_NTFS_IRP_CONTEXT_FLAG_SECONDARY_FILE ); Status = STATUS_SUCCESS; for (;;) { NDAS_ASSERT( secondaryRecoveryResourceAcquired == FALSE ); NDAS_ASSERT( secondaryResourceAcquired == FALSE ); if (!FlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT)) { Status = NtfsPostRequest( IrpContext, Irp ); break; } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->RecoveryResource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); try { SecondaryRecoverySessionStart( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->State, IRP_CONTEXT_STATE_WAIT) ); NDAS_ASSERT( secondaryResourceAcquired == TRUE ); break; } if (Status == STATUS_SUCCESS) { try { Status = NtfsCommonLockControl( IrpContext, Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Resource ); } } } else Status = NtfsCommonLockControl( IrpContext, Irp ); #else Status = NtfsCommonLockControl( IrpContext, Irp ); #endif break; } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT ||
NTSTATUS NdasFatSecondaryUserFsCtrl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for implementing the user's requests made through NtFsControlFile. Arguments: Irp - Supplies the Irp being processed Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; ULONG FsControlCode; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; UINT8 *ndfsWinxpRequestData; LARGE_INTEGER timeOut; struct FileSystemControl fileSystemControl; PVOID inputBuffer = NULL; ULONG inputBufferLength; PVOID outputBuffer = NULL; ULONG outputBufferLength; ULONG bufferLength; // // Save some references to make our life a little easier // FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; DebugTrace(+1, Dbg,"FatUserFsCtrl...\n", 0); DebugTrace( 0, Dbg,"FsControlCode = %08lx\n", FsControlCode); // // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode // of the caller was userspace and this is a METHOD_NEITHER, we have the choice // of realy buffering the request through so we can possibly post, or making the // request synchronous. Since the former was not done by design, do the latter. // if (Irp->RequestorMode != KernelMode && (FsControlCode & 3) == METHOD_NEITHER) { SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); } // // Case on the control code. // switch ( FsControlCode ) { case FSCTL_REQUEST_OPLOCK_LEVEL_1: case FSCTL_REQUEST_OPLOCK_LEVEL_2: case FSCTL_REQUEST_BATCH_OPLOCK: case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: case FSCTL_OPBATCH_ACK_CLOSE_PENDING: case FSCTL_OPLOCK_BREAK_NOTIFY: case FSCTL_OPLOCK_BREAK_ACK_NO_2: case FSCTL_REQUEST_FILTER_OPLOCK : //ASSERT( FALSE ); //Status = STATUS_SUCCESS; //break; Status = FatOplockRequest( IrpContext, Irp ); return Status; case FSCTL_LOCK_VOLUME: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdasFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatLockVolume( IrpContext, Irp ); break; case FSCTL_UNLOCK_VOLUME: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdasFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatUnlockVolume( IrpContext, Irp ); break; case FSCTL_DISMOUNT_VOLUME: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdasFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatDismountVolume( IrpContext, Irp ); break; case FSCTL_MARK_VOLUME_DIRTY: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdasFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatDirtyVolume( IrpContext, Irp ); break; case FSCTL_IS_VOLUME_DIRTY: Status = FatIsVolumeDirty( IrpContext, Irp ); break; case FSCTL_IS_VOLUME_MOUNTED: Status = FatIsVolumeMounted( IrpContext, Irp ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_IS_PATHNAME_VALID: Status = FatIsPathnameValid( IrpContext, Irp ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_QUERY_RETRIEVAL_POINTERS: Status = FatQueryRetrievalPointers( IrpContext, Irp ); break; case FSCTL_QUERY_FAT_BPB: Status = FatQueryBpb( IrpContext, Irp ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_FILESYSTEM_GET_STATISTICS: Status = FatGetStatistics( IrpContext, Irp ); break; case FSCTL_GET_VOLUME_BITMAP: Status = FatGetVolumeBitmap( IrpContext, Irp ); break; case FSCTL_GET_RETRIEVAL_POINTERS: Status = FatGetRetrievalPointers( IrpContext, Irp ); break; case FSCTL_MOVE_FILE: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = FatMoveFile( IrpContext, Irp ); break; case FSCTL_ALLOW_EXTENDED_DASD_IO: Status = FatAllowExtendedDasdIo( IrpContext, Irp ); break; default : DebugTrace(0, Dbg, "Invalid control code -> %08lx\n", FsControlCode ); FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); Status = STATUS_INVALID_DEVICE_REQUEST; break; } ASSERT( !ExIsResourceAcquiredSharedLite(&volDo->Vcb.Resource) ); if (Status != STATUS_SUCCESS) { DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; } inputBuffer = IrpContext->InputBuffer; outputBuffer = IrpContext->outputBuffer; ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength ? (inputBuffer != NULL) : (inputBuffer == NULL) ); ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength ? (outputBuffer != NULL) : (outputBuffer == NULL) ); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { return FatFsdPostRequest( IrpContext, Irp ); } try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->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 ); NDAS_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ASSERT( IS_SECONDARY_FILEOBJECT(IrpSp->FileObject) ); typeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &vcb, &fcb, &ccb ); if (FlagOn(ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { ASSERT( FlagOn(ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); try_return( Status = STATUS_FILE_CORRUPT_ERROR ); } fileSystemControl.FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; fileSystemControl.InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; fileSystemControl.OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; if (inputBuffer == NULL) fileSystemControl.InputBufferLength = 0; if (outputBuffer == NULL) fileSystemControl.OutputBufferLength = 0; outputBufferLength = fileSystemControl.OutputBufferLength; if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 inputBufferLength = 0; } else if (fileSystemControl.FsControlCode == FSCTL_MARK_HANDLE) { // 63 inputBufferLength = 0; } else { inputBufferLength = fileSystemControl.InputBufferLength; } bufferLength = (inputBufferLength >= outputBufferLength) ? inputBufferLength : outputBufferLength; secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_FILE_SYSTEM_CONTROL, bufferLength ); if (secondaryRequest == NULL) { NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES ); Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; try_return( Status ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FILE_SYSTEM_CONTROL, inputBufferLength ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, Irp, IrpSp, ccb->PrimaryFileHandle ); ndfsWinxpRequestHeader->FileSystemControl.OutputBufferLength = fileSystemControl.OutputBufferLength; ndfsWinxpRequestHeader->FileSystemControl.InputBufferLength = fileSystemControl.InputBufferLength; ndfsWinxpRequestHeader->FileSystemControl.FsControlCode = fileSystemControl.FsControlCode; #if 0 if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 PMOVE_FILE_DATA moveFileData = inputBuffer; PFILE_OBJECT moveFileObject; PCCB moveCcb; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if (Status != STATUS_SUCCESS) { ASSERT( FALSE ); try_return( Status ); } ObDereferenceObject( moveFileObject ); moveCcb = moveFileObject->FsContext2; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.FileHandle = moveCcb->PrimaryFileHandle; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.StartingVcn = moveFileData->StartingVcn.QuadPart; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.StartingLcn = moveFileData->StartingLcn.QuadPart; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.ClusterCount = moveFileData->ClusterCount; } else #endif if (fileSystemControl.FsControlCode == FSCTL_MARK_HANDLE) { // 63 PMARK_HANDLE_INFO markHandleInfo = inputBuffer; PFILE_OBJECT volumeFileObject; PCCB volumeCcb; Status = ObReferenceObjectByHandle( markHandleInfo->VolumeHandle, FILE_READ_DATA, 0, KernelMode, &volumeFileObject, NULL ); if (Status != STATUS_SUCCESS) { try_return( Status ); } ObDereferenceObject( volumeFileObject ); volumeCcb = volumeFileObject->FsContext2; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.UsnSourceInfo = markHandleInfo->UsnSourceInfo; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.VolumeHandle = volumeCcb->PrimaryFileHandle; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.HandleInfo = markHandleInfo->HandleInfo; } else { ndfsWinxpRequestData = (UINT8 *)(ndfsWinxpRequestHeader+1); if (inputBufferLength) RtlCopyMemory( ndfsWinxpRequestData, inputBuffer, inputBufferLength ); } ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { secondaryRequest = NULL; try_return( Status = STATUS_IO_DEVICE_ERROR ); } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); NDAS_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; Status = Irp->IoStatus.Status = NTOHL(ndfsWinxpReplytHeader->Status4); Irp->IoStatus.Information = NTOHL(ndfsWinxpReplytHeader->Information32); if (FsControlCode == FSCTL_GET_NTFS_VOLUME_DATA && Status != STATUS_SUCCESS) DebugTrace2( 0, Dbg2, ("FSCTL_GET_NTFS_VOLUME_DATA: Status = %x, Irp->IoStatus.Information = %d\n", Status, Irp->IoStatus.Information) ); if (NTOHL(secondaryRequest->NdfsReplyHeader.MessageSize4) - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REPLY_HEADER)) { ASSERT( Irp->IoStatus.Status == STATUS_SUCCESS || Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ); ASSERT( Irp->IoStatus.Information ); ASSERT( Irp->IoStatus.Information <= outputBufferLength ); ASSERT( outputBuffer ); RtlCopyMemory( outputBuffer, (UINT8 *)(ndfsWinxpReplytHeader+1), Irp->IoStatus.Information ); } if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE && Status != STATUS_SUCCESS) DebugTrace2( 0, Dbg2, ("NtfsDefragFile: status = %x\n", Status) ); #if 0 if (Status == STATUS_SUCCESS && fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 PMOVE_FILE_DATA moveFileData = inputBuffer; PFILE_OBJECT moveFileObject; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB moveFcb; PSCB moveScb; PCCB moveCcb; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if (Status != STATUS_SUCCESS) { try_return( Status ); } ObDereferenceObject( moveFileObject ); typeOfOpen = NtfsDecodeFileObject( IrpContext, moveFileObject, &vcb, &moveFcb, &moveScb, &moveCcb, TRUE ); if (typeOfOpen == UserFileOpen && FlagOn(volDo->NdasFatFlags, ND_FAT_DEVICE_FLAG_DIRECT_RW) && ndfsWinxpReplytHeader->FileInformationSet && NTOHLL(ndfsWinxpReplytHeader->AllocationSize8)) { PNDFS_FAT_MCB_ENTRY mcbEntry; ULONG index; VCN testVcn; SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ); NtfsAcquireFcbWithPaging( IrpContext, moveFcb, 0 ); NtfsAcquireNtfsMcbMutex( &moveScb->Mcb ); mcbEntry = (PNDFS_FAT_MCB_ENTRY)( ndfsWinxpReplytHeader+1 ); if (moveScb->Header.AllocationSize.QuadPart) { NtfsRemoveNtfsMcbEntry( &moveScb->Mcb, 0, 0xFFFFFFFF ); } for (index=0, testVcn=0; index < NTOHL(ndfsWinxpReplytHeader->NumberOfMcbEntry4); index++) { ASSERT( mcbEntry[index].Vcn == testVcn ); testVcn += (LONGLONG)mcbEntry[index].ClusterCount; NtfsAddNtfsMcbEntry( &moveScb->Mcb, mcbEntry[index].Vcn, (mcbEntry[index].Lcn << vcb->AllocationSupport.LogOfBytesPerSector), (LONGLONG)mcbEntry[index].ClusterCount, TRUE ); } ASSERT( LlBytesFromClusters(vcb, testVcn) == NTOHLL(ndfsWinxpReplytHeader->AllocationSize8) ); if (moveScb->Header.AllocationSize.QuadPart != NTOHLL(ndfsWinxpReplytHeader->AllocationSize8)) SetFlag( moveScb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE ); moveScb->Header.FileSize.LowPart = NTOHLL(ndfsWinxpReplytHeader->FileSize8); moveScb->Header.AllocationSize.QuadPart = NTOHLL(ndfsWinxpReplytHeader->AllocationSize8); ASSERT( moveScb->Header.AllocationSize.QuadPart >= moveScb->Header.FileSize.LowPart ); if (moveFileObject->SectionObjectPointer->DataSectionObject != NULL && moveFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( moveFileObject, (PCC_FILE_SIZES)&moveScb->Header.AllocationSize, FALSE, &NtfsData.CacheManagerCallbacks, moveScb ); //CcSetAdditionalCacheAttributes( fileObject, TRUE, TRUE ); } if (CcIsFileCached(moveFileObject)) { NtfsSetBothCacheSizes( moveFileObject, (PCC_FILE_SIZES)&scb->Header.AllocationSize, moveScb ); } NtfsReleaseNtfsMcbMutex( &moveScb->Mcb ); NtfsReleaseFcb( IrpContext, moveFcb ); } } #endif try_exit: NOTHING; } finally { if (secondarySessionResourceAcquired == TRUE) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } FatCompleteRequest( IrpContext, Irp, Status ); DebugTrace(-1, Dbg, "FatUserFsCtrl -> %08lx\n", Status ); return Status; }
/* RETURN True if current thread owns the lock (possibly shared) */ BOOL FASTCALL UserIsEntered(VOID) { return ExIsResourceAcquiredExclusiveLite(&UserLock) || ExIsResourceAcquiredSharedLite(&UserLock); }
NTSTATUS FatCommonClose ( IN PVCB Vcb, IN PFCB Fcb, IN PCCB Ccb, IN TYPE_OF_OPEN TypeOfOpen, IN BOOLEAN Wait, OUT PBOOLEAN VcbDeleted OPTIONAL ) /*++ Routine Description: This is the common routine for closing a file/directory called by both the fsd and fsp threads. Close is invoked whenever the last reference to a file object is deleted. Cleanup is invoked when the last handle to a file object is closed, and is called before close. The function of close is to completely tear down and remove the fcb/dcb/ccb structures associated with the file object. Arguments: Fcb - Supplies the file to process. Wait - If this is TRUE we are allowed to block for the Vcb, if FALSE then we must try to acquire the Vcb anyway. VcbDeleted - Returns whether the VCB was deleted by this call. Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PDCB ParentDcb; BOOLEAN RecursiveClose; BOOLEAN LocalVcbDeleted; IRP_CONTEXT IrpContext; #if __NDAS_FAT_SECONDARY__ BOOLEAN volDoResourceAcquired = FALSE; BOOLEAN send2Primary = FALSE; BOOLEAN volDoCcb = FALSE; _U64 primaryFileHandle; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN volDoSessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; #endif PAGED_CODE(); DebugTrace(+1, Dbg, "FatCommonClose...\n", 0); // // Initailize the callers variable, if needed. // LocalVcbDeleted = FALSE; if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } // // Special case the unopened file object // if (TypeOfOpen == UnopenedFileObject) { DebugTrace(0, Dbg, "Close unopened file object\n", 0); Status = STATUS_SUCCESS; DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); return Status; } // // Set up our stack IrpContext. // RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT; IrpContext.NodeByteSize = sizeof( IrpContext ); IrpContext.MajorFunction = IRP_MJ_CLOSE; IrpContext.Vcb = Vcb; if (Wait) { SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); } #if __NDAS_FAT_SECONDARY__ if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) SetFlag( IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { if (!FlagOn(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT)) { return STATUS_PENDING; } volDoResourceAcquired = SecondaryAcquireResourceSharedStarveExclusiveLite( &IrpContext, &volDo->Resource, BooleanFlagOn(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT) ); if (volDoResourceAcquired == FALSE) { ASSERT( FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ); // It's not always garented continue; return STATUS_PENDING; } } if (volDo->NetdiskEnableMode == NETDISK_SECONDARY && !FlagOn(volDo->NetdiskPartitionInformation.Flags, NETDISK_PARTITION_INFORMATION_FLAG_INDIRECT)) { if (TypeOfOpen == VirtualVolumeFile || TypeOfOpen == DirectoryFile) { SetFlag( IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); } } #endif // // Acquire exclusive access to the Vcb and enqueue the irp if we didn't // get access. // #if __NDAS_FAT_SECONDARY__ if (!(FlagOn(IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT) ? ExAcquireResourceExclusiveLite( &Vcb->SecondaryResource, Wait ) : ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait ))) { if (volDoResourceAcquired) { ASSERT( ExIsResourceAcquiredSharedLite(&volDo->Resource) ); SecondaryReleaseResourceLite( NULL, &volDo->Resource ); } return STATUS_PENDING; } #else if (!ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait )) { return STATUS_PENDING; } #endif // // The following test makes sure that we don't blow away an Fcb if we // are trying to do a Supersede/Overwrite open above us. This test // does not apply for the EA file. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) && Vcb->EaFcb != Fcb) { #if __NDAS_FAT_SECONDARY__ if (FlagOn(IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT)) ExReleaseResourceLite( &Vcb->SecondaryResource ); else ExReleaseResourceLite( &Vcb->Resource ); if (volDoResourceAcquired) { ASSERT( ExIsResourceAcquiredSharedLite(&volDo->Resource) ); SecondaryReleaseResourceLite( NULL, &volDo->Resource ); } #else ExReleaseResourceLite( &Vcb->Resource ); #endif return STATUS_PENDING; } // // Setting the following flag prevents recursive closes of directory file // objects, which are handled in a special case loop. // if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS) ) { RecursiveClose = TRUE; } else { SetFlag(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS); RecursiveClose = FALSE; // // Since we are at the top of the close chain, we need to add // a reference to the VCB. This will keep it from going away // on us until we are ready to check for a dismount below. // Vcb->OpenFileCount += 1; } try { // // Case on the type of open that we are trying to close. // switch (TypeOfOpen) { case VirtualVolumeFile: DebugTrace(0, Dbg, "Close VirtualVolumeFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( &(Vcb->InternalOpenCount) ); InterlockedDecrement( &(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case UserVolumeOpen: DebugTrace(0, Dbg, "Close UserVolumeOpen\n", 0); #if __NDAS_FAT_SECONDARY__ if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { volDoCcb = TRUE; if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { if ( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ) Fcb->CorruptedCcbCloseCount --; send2Primary = FALSE; } else send2Primary = TRUE; primaryFileHandle = Ccb->PrimaryFileHandle; ExAcquireFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); RemoveEntryList( &Ccb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); InitializeListHead( &Ccb->ListEntry ); Ccb->FileObject = NULL; if (Ccb->Buffer) ExFreePool( Ccb->Buffer ); Ccb->FileObject = NULL; InterlockedDecrement( &Vcb->SecondaryOpenFileCount ); } else { Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } } if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_OPEN_BY_PRIMARY_SESSION)) { InterlockedDecrement( &Vcb->PrimaryOpenFileCount ); } FatDeleteCcb( &IrpContext, &Ccb ); if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { InterlockedDecrement( &Fcb->OpenCount ); if (Fcb->OpenCount == 0) { ExAcquireFastMutex( &volDo->Secondary->FcbQMutex ); RemoveEntryList( &Fcb->ListEntry ); InitializeListHead( &Fcb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->FcbQMutex ); Fcb->Header.NodeTypeCode = FAT_NTC_FCB; FatDeleteFcb( &IrpContext, &Fcb ); Secondary_Dereference( volDo->Secondary ); } } else { try_return( Status = STATUS_SUCCESS ); } #else Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); try_return( Status = STATUS_SUCCESS ); #endif break; case EaFile: DebugTrace(0, Dbg, "Close EaFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( &(Vcb->InternalOpenCount) ); InterlockedDecrement( &(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case DirectoryFile: DebugTrace(0, Dbg, "Close DirectoryFile\n", 0); InterlockedDecrement( &Fcb->Specific.Dcb.DirectoryFileOpenCount ); // // Remove this internal open from the count. // InterlockedDecrement( &(Vcb->InternalOpenCount) ); // // If this is the root directory, it is a residual open // as well. // if (NodeType( Fcb ) == FAT_NTC_ROOT_DCB) { InterlockedDecrement( &(Vcb->ResidualOpenCount) ); } // // If this is a recursive close, just return here. // if ( RecursiveClose ) { try_return( Status = STATUS_SUCCESS ); } else { break; } case UserDirectoryOpen: case UserFileOpen: DebugTrace(0, Dbg, "Close UserFileOpen/UserDirectoryOpen\n", 0); // // Uninitialize the cache map if we no longer need to use it // if ((NodeType(Fcb) == FAT_NTC_DCB) && IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) && (Fcb->OpenCount == 1) && (Fcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject = Fcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize the stream file object\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); // // Dereference the directory file. This may cause a close // Irp to be processed, so we need to do this before we destory // the Fcb. // Fcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); } #if __NDAS_FAT__ if (TypeOfOpen == UserFileOpen) { ExAcquireFastMutex( &Fcb->NonPaged->CcbQMutex ); Ccb->FileObject = NULL; Ccb->Fcb = NULL; RemoveEntryList( &Ccb->FcbListEntry ); InitializeListHead( &Ccb->FcbListEntry ); ExReleaseFastMutex( &Fcb->NonPaged->CcbQMutex ); } #endif Fcb->OpenCount -= 1; #if __NDAS_FAT_SECONDARY__ if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { volDoCcb = TRUE; if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { if ( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ) Fcb->CorruptedCcbCloseCount --; send2Primary = FALSE; } else send2Primary = TRUE; primaryFileHandle = Ccb->PrimaryFileHandle; ExAcquireFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); RemoveEntryList( &Ccb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); InitializeListHead( &Ccb->ListEntry ); Ccb->FileObject = NULL; if (Ccb->Buffer) ExFreePool( Ccb->Buffer ); InterlockedDecrement( &Vcb->SecondaryOpenFileCount ); Ccb->FileObject = NULL; } else { Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } } if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_OPEN_BY_PRIMARY_SESSION)) { InterlockedDecrement( &Vcb->PrimaryOpenFileCount ); } FatDeleteCcb( &IrpContext, &Ccb ); if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { if (Fcb->OpenCount == 0) { ExAcquireFastMutex( &volDo->Secondary->FcbQMutex ); RemoveEntryList( &Fcb->ListEntry ); InitializeListHead( &Fcb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->FcbQMutex ); Fcb->Header.NodeTypeCode = FAT_NTC_FCB; FatDeleteFcb( &IrpContext, &Fcb ); Secondary_Dereference( volDo->Secondary ); } } #else Fcb->OpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); #endif break; default: FatBugCheck( TypeOfOpen, 0, 0 ); } #if __NDAS_FAT_SECONDARY__ if (send2Primary) { Status = STATUS_SUCCESS; volDoSessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( &IrpContext, &volDo->SessionResource, BooleanFlagOn(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(volDo->Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { Status = STATUS_SUCCESS; leave; } secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_CLOSE, 0 ); if (secondaryRequest == NULL) { ASSERT( FALSE ); leave; } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_CLOSE, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Fcb; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_CLOSE; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = primaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); KeClearEvent( &secondaryRequest->CompleteEvent ); if (Status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); } if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) { ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; ASSERT( ndfsWinxpReplytHeader->Status == STATUS_SUCCESS ); leave; } ASSERT( secondaryRequest->ExecuteStatus != STATUS_SUCCESS ); } if (volDoCcb == TRUE) { Status = STATUS_SUCCESS; leave; } #endif // // At this point we've cleaned up any on-disk structure that needs // to be done, and we can now update the in-memory structures. // Now if this is an unreferenced FCB or if it is // an unreferenced DCB (not the root) then we can remove // the fcb and set our ParentDcb to non null. // if (((NodeType(Fcb) == FAT_NTC_FCB) && (Fcb->OpenCount == 0)) || ((NodeType(Fcb) == FAT_NTC_DCB) && (IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) && (Fcb->OpenCount == 0) && (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0))) { ParentDcb = Fcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &Fcb ); // // Uninitialize our parent's cache map if we no longer need // to use it. // while ((NodeType(ParentDcb) == FAT_NTC_DCB) && IsListEmpty(&ParentDcb->Specific.Dcb.ParentDcbQueue) && (ParentDcb->OpenCount == 0) && (ParentDcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject; DirectoryFileObject = ParentDcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); ParentDcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); // // Now, if the ObDereferenceObject() caused the final close // to come in, then blow away the Fcb and continue up, // otherwise wait for Mm to to dereference its file objects // and stop here.. // if ( ParentDcb->Specific.Dcb.DirectoryFileOpenCount == 0) { PDCB CurrentDcb; CurrentDcb = ParentDcb; ParentDcb = CurrentDcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &CurrentDcb ); } else { break; } } } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { DebugUnwind( FatCommonClose ); #if __NDAS_FAT_SECONDARY__ if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); if (volDoSessionResourceAcquired) { SecondaryReleaseResourceLite( &IrpContext, &volDo->SessionResource ); } if (volDoResourceAcquired) { ASSERT( ExIsResourceAcquiredSharedLite(&volDo->Resource) ); SecondaryReleaseResourceLite( NULL, &volDo->Resource ); } #endif // // We are done processing the close. If we are the top of the close // chain, see if the VCB can go away. We have biased the open count by // one, so we need to take that into account. // if (!RecursiveClose) { // // See if there is only one open left. If so, it is ours. We only want // to check for a dismount if a dismount is not already in progress. // We also only do this if the caller can handle the VCB going away. // This is determined by whether they passed in the VcbDeleted argument. // if (Vcb->OpenFileCount == 1 && !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) && ARGUMENT_PRESENT( VcbDeleted )) { // // We need the global lock, which must be acquired before the // VCB. Since we already have the VCB, we have to drop and // reaquire here. Note that we always want to wait from this // point on. Note that the VCB cannot go away, since we have // biased the open file count. // FatReleaseVcb( &IrpContext, Vcb ); SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); FatAcquireExclusiveGlobal( &IrpContext ); FatAcquireExclusiveVcb( &IrpContext, Vcb ); // // We have our locks in the correct order. Remove our // extra open and check for a dismount. Note that if // something changed while we dropped the lock, it will // not matter, since the dismount code does the correct // checks to make sure the volume can really go away. // Vcb->OpenFileCount -= 1; LocalVcbDeleted = FatCheckForDismount( &IrpContext, Vcb, FALSE ); FatReleaseGlobal( &IrpContext ); // // Let the caller know what happened, if they want this information. // if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } } else { // // The volume cannot go away now. Just remove our extra reference. // Vcb->OpenFileCount -= 1; } // // If the VCB is still around, clear our recursion flag. // if (!LocalVcbDeleted) { ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS ); } } // // Only release the VCB if it did not go away. // if (!LocalVcbDeleted) { FatReleaseVcb( &IrpContext, Vcb ); } DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); } return Status; }
NTSTATUS NdFatSecondaryCommonWrite ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS status; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT fileObject = irpSp->FileObject; struct Write write; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; BOOLEAN fcbAcquired = FALSE; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); typeOfOpen = FatDecodeFileObject( fileObject, &vcb, &fcb, &ccb ); ASSERT( typeOfOpen == UserFileOpen ); if (FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { /*if (FlagOn( fcb->FcbState, FCB_STATE_FILE_DELETED )) { ASSERT( FALSE ); FatRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL ); } else */{ ASSERT( FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); return STATUS_FILE_CORRUPT_ERROR; } } if (irpSp->Parameters.Write.ByteOffset.QuadPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1) { write.ByteOffset = fcb->Header.FileSize; } else { write.ByteOffset = irpSp->Parameters.Write.ByteOffset; } write.Key = 0; write.Length = irpSp->Parameters.Write.Length; if (FlagOn(Irp->Flags, IRP_PAGING_IO)) { ASSERT( (write.ByteOffset.QuadPart + write.Length) <= ((fcb->Header.AllocationSize.QuadPart + PAGE_SIZE - 1) & ~((LONGLONG) (PAGE_SIZE-1))) ); return STATUS_SUCCESS; } ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); //ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_LAZY_WRITE ) ); if ( (write.ByteOffset.QuadPart + write.Length) <= fcb->Header.FileSize.LowPart) { return STATUS_SUCCESS; } if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { return STATUS_PENDING; ASSERT( FALSE ); DebugTrace2( 0, Dbg, ("Can't wait in NdFatSecondaryCommonWrite\n") ); status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace2( -1, Dbg2, ("NdFatSecondaryCommonWrite: FatFsdPostRequest -> %08lx\n", status) ); return status; } DebugTrace2( 0, Dbg, ("write.ByteOffset.QuadPart + write.Length > fcb->Header.AllocationSize.QuadPart = %d " "ExIsResourceAcquiredSharedLite(fcb->Header.Resource) = %d\n", ((write.ByteOffset.QuadPart + write.Length) > fcb->Header.AllocationSize.QuadPart), ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) ); if ((write.ByteOffset.QuadPart + write.Length) > fcb->Header.AllocationSize.QuadPart) { FatAcquireExclusiveFcb( IrpContext, fcb ); fcbAcquired = TRUE; } try { 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( Dbg, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_SET_INFORMATION, volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize ); if (secondaryRequest == NULL) { FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_SET_INFORMATION, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Irp; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_SET_INFORMATION; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = ccb->PrimaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; ndfsWinxpRequestHeader->SetFile.FileHandle = 0; ndfsWinxpRequestHeader->SetFile.Length = sizeof( FILE_END_OF_FILE_INFORMATION ); ndfsWinxpRequestHeader->SetFile.FileInformationClass = FileEndOfFileInformation; ndfsWinxpRequestHeader->SetFile.EndOfFileInformation.EndOfFile = write.ByteOffset.QuadPart + write.Length; 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) { secondaryRequest = NULL; status = STATUS_IO_DEVICE_ERROR; leave; } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; status = ndfsWinxpReplytHeader->Status; Irp->IoStatus.Information = write.Length; if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { DebugTrace2( 0, Dbg2, ("NdNtfsSecondaryCommonWrite: ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); ASSERT( ndfsWinxpReplytHeader->Information == 0 ); } else ASSERT( ndfsWinxpReplytHeader->FileInformationSet ); if (ndfsWinxpReplytHeader->FileInformationSet) { PNDFS_FAT_MCB_ENTRY mcbEntry; ULONG index; BOOLEAN lookupResut; VBO vcn; LBO lcn; //LBO startingLcn; ULONG clusterCount; //DbgPrint( "w ndfsWinxpReplytHeader->FileSize = %x\n", ndfsWinxpReplytHeader->FileSize ); if (ndfsWinxpReplytHeader->AllocationSize != fcb->Header.AllocationSize.QuadPart) { ASSERT( ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource) ); ASSERT( ndfsWinxpReplytHeader->AllocationSize > fcb->Header.AllocationSize.QuadPart ); mcbEntry = (PNDFS_FAT_MCB_ENTRY)( ndfsWinxpReplytHeader+1 ); for (index=0, vcn=0; index < ndfsWinxpReplytHeader->NumberOfMcbEntry; index++, mcbEntry++) { lookupResut = FatLookupMcbEntry( vcb, &fcb->Mcb, vcn, &lcn, &clusterCount, NULL ); if (lookupResut == TRUE && vcn < fcb->Header.AllocationSize.QuadPart) { ASSERT( lookupResut == TRUE ); //ASSERT( startingLcn == lcn ); ASSERT( vcn == mcbEntry->Vcn ); ASSERT( lcn == (((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector) ); ASSERT( clusterCount <= mcbEntry->ClusterCount ); if (clusterCount < mcbEntry->ClusterCount) { FatAddMcbEntry ( vcb, &fcb->Mcb, (VBO)mcbEntry->Vcn, ((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector, (ULONG)mcbEntry->ClusterCount ); lookupResut = FatLookupMcbEntry( vcb, &fcb->Mcb, vcn, &lcn, &clusterCount, NULL ); ASSERT( lookupResut == TRUE ); //ASSERT( startingLcn == lcn ); ASSERT( vcn == mcbEntry->Vcn ); ASSERT( lcn == (((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector) ); ASSERT( clusterCount == mcbEntry->ClusterCount ); } } else { ASSERT( lookupResut == FALSE || lcn == 0 ); FatAddMcbEntry ( vcb, &fcb->Mcb, (VBO)mcbEntry->Vcn, ((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector, (ULONG)mcbEntry->ClusterCount ); } vcn += (ULONG)mcbEntry->ClusterCount; } ASSERT( vcn == ndfsWinxpReplytHeader->AllocationSize ); fcb->Header.AllocationSize.QuadPart = ndfsWinxpReplytHeader->AllocationSize; SetFlag( fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE ); if (CcIsFileCached(fileObject)) { ASSERT( fileObject->SectionObjectPointer->SharedCacheMap != NULL ); CcSetFileSizes( fileObject, (PCC_FILE_SIZES)&fcb->Header.AllocationSize ); } } DebugTrace2(0, Dbg, ("write scb->Header.FileSize.LowPart = %I64x, scb->Header.ValidDataLength.QuadPart = %I64x\n", fcb->Header.FileSize.LowPart, fcb->Header.ValidDataLength.QuadPart) ); } #if DBG { BOOLEAN lookupResut; VBO vcn; LBO lcn; //LCN startingLcn; ULONG clusterCount; vcn = 0; while (1) { lookupResut = FatLookupMcbEntry( vcb, &fcb->Mcb, vcn, &lcn, &clusterCount, NULL ); if (lookupResut == FALSE || lcn == 0) break; vcn += clusterCount; } ASSERT( vcn == fcb->Header.AllocationSize.QuadPart ); } #endif } finally { if (secondarySessionResourceAcquired == TRUE) SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); if (fcbAcquired) { FatReleaseFcb( IrpContext, fcb ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } return status; }
NTSTATUS FatFsdFlushBuffers ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of Flush buffers. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being flushed exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel; PAGED_CODE(); DebugTrace(+1, Dbg, "FatFsdFlushBuffers\n", 0); // // Call the common Cleanup routine, with blocking allowed if synchronous // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); #ifdef __ND_FAT__ do { try { if (IrpContext == NULL) { IrpContext = FatCreateIrpContext( Irp, CanFsdWait(Irp) ); IrpContext->TopLevel = TopLevel; } #ifdef __ND_FAT_SECONDARY__ if (IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( FatIsTopLevelRequest(IrpContext) ); #ifdef __ND_FAT_DBG__ ASSERT( FlagOn(IrpContext->NdFatFlags, ND_FAT_IRP_CONTEXT_FLAG_SECONDARY_FILE) ); #endif Status = STATUS_SUCCESS; while (TRUE) { ASSERT( secondaryRecoveryResourceAcquired == FALSE ); ASSERT( secondaryResourceAcquired == FALSE ); if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { if(!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Secondary->RecoveryResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Secondary->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Secondary->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); try { SessionRecovery( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Secondary->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Secondary->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Secondary->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (secondaryResourceAcquired == FALSE) { ASSERT( FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING) ); continue; } break; } if (Status == STATUS_SUCCESS) { try { Status = FatCommonFlushBuffers( IrpContext, Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Secondary->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->Resource ); } } } else Status = FatCommonFlushBuffers( IrpContext, Irp ); #else Status = FatCommonFlushBuffers( IrpContext, Irp ); #endif break; } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT);
BOOLEAN FatIsCurrentOperationSynchedForDcbTeardown ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb ) { PIRP Irp = IrpContext->OriginatingIrp; PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation( Irp ) ; PFILE_OBJECT FileObject = Stack->FileObject; PVCB Vcb; PFCB Fcb; PCCB Ccb; PFILE_OBJECT ToCheck[3]; ULONG Index = 0; PAGED_CODE(); // // While mounting, we're OK without having to own anything. // if (Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && Stack->MinorFunction == IRP_MN_MOUNT_VOLUME) { return TRUE; } // // With the Vcb held, the close path is blocked out. // if (ExIsResourceAcquiredSharedLite( &Dcb->Vcb->Resource ) || ExIsResourceAcquiredExclusiveLite( &Dcb->Vcb->Resource )) { return TRUE; } // // Accept this assertion at face value. It comes from GetDirentForFcbOrDcb, // and is reliable. // if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD )) { return TRUE; } // // Determine which fileobjects are around on this operation. // if (Stack->MajorFunction == IRP_MJ_SET_INFORMATION && Stack->Parameters.SetFile.FileObject) { ToCheck[Index++] = Stack->Parameters.SetFile.FileObject; } if (Stack->FileObject) { ToCheck[Index++] = Stack->FileObject; } ToCheck[Index] = NULL; // // If the fileobjects we have are for this dcb or a child of it, we are // also guaranteed that this dcb isn't going anywhere (even without // the Vcb). // for (Index = 0; ToCheck[Index] != NULL; Index++) { (VOID) FatDecodeFileObject( ToCheck[Index], &Vcb, &Fcb, &Ccb ); while ( Fcb ) { if (Fcb == Dcb) { return TRUE; } Fcb = Fcb->ParentDcb; } } return FatDisableParentCheck; }
NTSTATUS FatFsdQueryVolumeInformation ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the Fsd part of the NtQueryVolumeInformation API call. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being queried exists. Irp - Supplies the Irp being processed. Return Value: NTSTATUS - The FSD status for the Irp. --*/ { NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel; PAGED_CODE(); #if __NDAS_FAT__ if ((PVOID)FatControlDeviceObject == VolumeDeviceObject) { Status = Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return Status; } #endif DebugTrace(+1, Dbg, "FatFsdQueryVolumeInformation\n", 0); // // Call the common query routine, with blocking allowed if synchronous // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); #if (__NDAS_FAT_PRIMARY__ || __NDAS_FAT_SECONDARY__) do { try { if (IrpContext == NULL) { IrpContext = FatCreateIrpContext( Irp, CanFsdWait(Irp) ); IrpContext->TopLevel = TopLevel; } #if __NDAS_FAT_SECONDARY__ if (IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN volDoResourceAcquired = FALSE; BOOLEAN volDoRecoveryResourceAcquired = FALSE; ASSERT( FatIsTopLevelRequest(IrpContext) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); Status = STATUS_SUCCESS; for (;;) { NDAS_ASSERT( volDoRecoveryResourceAcquired == FALSE ); NDAS_ASSERT( volDoResourceAcquired == FALSE ); if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = FatFsdPostRequest( IrpContext, Irp ); break; } if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { volDoRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->RecoveryResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); volDoRecoveryResourceAcquired = FALSE; continue; } volDoResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); try { SecondaryRecoverySessionStart( VolumeDeviceObject->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->Resource ); volDoResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolumeDeviceObject->RecoveryResource ); volDoRecoveryResourceAcquired = FALSE; } continue; } volDoResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolumeDeviceObject->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); NDAS_ASSERT( volDoResourceAcquired == TRUE ); break; } if (Status == STATUS_SUCCESS) { try { Status = FatCommonQueryVolumeInfo( IrpContext, Irp ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Resource ); } } } else Status = FatCommonQueryVolumeInfo( IrpContext, Irp ); #else Status = FatCommonQueryVolumeInfo( IrpContext, Irp ); #endif break; } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT);
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; }
VOID NtfsUpdateScbFromFileObject ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PSCB Scb, IN BOOLEAN CheckTimeStamps ) /*++ Routine Description: This routine is called to update the Scb/Fcb to reflect the changes to a file through the fast io path. It only called with a file object which represents a user's handle. Arguments: FileObject - This is the file object used in the fast io path. Scb - This is the Scb for this stream. CheckTimeStamps - Indicates whether we want to update the time stamps from the fast io flags as well. This will be TRUE if our caller will update the standard information, attribute header and duplicate info. FALSE if only the attribute header and duplicate info. The latter case is the valid data length callback from the cache manager. Return Value: None. --*/ { PFCB Fcb = Scb->Fcb; ULONG CcbFlags; ULONG ScbFlags = 0; LONGLONG CurrentTime; // // If the size of the main data stream is not part of the Fcb then update it // now and set the correct Fcb flag. // if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) { if (Fcb->Info.FileSize != Scb->Header.FileSize.QuadPart) { Fcb->Info.FileSize = Scb->Header.FileSize.QuadPart; SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_SIZE ); } if (Fcb->Info.AllocatedLength != Scb->TotalAllocated) { Fcb->Info.AllocatedLength = Scb->TotalAllocated; SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE ); } if (FlagOn( FileObject->Flags, FO_FILE_SIZE_CHANGED )) { SetFlag( ScbFlags, SCB_STATE_CHECK_ATTRIBUTE_SIZE ); } // // Remember to update the size in the attribute header for named streams as well. // } else if (FlagOn( FileObject->Flags, FO_FILE_SIZE_CHANGED )) { SetFlag( ScbFlags, SCB_STATE_NOTIFY_RESIZE_STREAM | SCB_STATE_CHECK_ATTRIBUTE_SIZE ); } ClearFlag( FileObject->Flags, FO_FILE_SIZE_CHANGED ); // // Check whether to update the time stamps if our caller requested it. // if (CheckTimeStamps && !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) { BOOLEAN UpdateLastAccess = FALSE; BOOLEAN UpdateLastChange = FALSE; BOOLEAN UpdateLastModify = FALSE; BOOLEAN SetArchive = TRUE; // // Copy the Ccb flags to a local variable. Then we won't have to test // for the existence of the Ccb each time. // CcbFlags = 0; // // Capture the real flags if present and clear them since we will update the Scb/Fcb. // if (FileObject->FsContext2 != NULL) { CcbFlags = ((PCCB) FileObject->FsContext2)->Flags; ClearFlag( ((PCCB) FileObject->FsContext2)->Flags, (CCB_FLAG_UPDATE_LAST_MODIFY | CCB_FLAG_UPDATE_LAST_CHANGE | CCB_FLAG_SET_ARCHIVE) ); } NtfsGetCurrentTime( IrpContext, CurrentTime ); // // If there was a write to the file then update the last change, last access // and last write and the archive bit. // if (FlagOn( FileObject->Flags, FO_FILE_MODIFIED )) { UpdateLastModify = UpdateLastAccess = UpdateLastChange = TRUE; // // Otherwise test each of the individual bits in the file object and // Ccb. // } else { if (FlagOn( FileObject->Flags, FO_FILE_FAST_IO_READ )) { UpdateLastAccess = TRUE; } if (FlagOn( CcbFlags, CCB_FLAG_UPDATE_LAST_CHANGE )) { UpdateLastChange = TRUE; if (FlagOn( CcbFlags, CCB_FLAG_UPDATE_LAST_MODIFY )) { UpdateLastModify = TRUE; } if (!FlagOn( CcbFlags, CCB_FLAG_SET_ARCHIVE )) { SetArchive = FALSE; } } } // // Now set the correct Fcb bits. // if (UpdateLastChange) { if (SetArchive) { ASSERTMSG( "conflict with flush", ExIsResourceAcquiredSharedLite( Fcb->Resource ) || (Fcb->PagingIoResource != NULL && ExIsResourceAcquiredSharedLite( Fcb->PagingIoResource ))); SetFlag( Fcb->Info.FileAttributes, FILE_ATTRIBUTE_ARCHIVE ); SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_FILE_ATTR ); SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO ); } if (!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_CHANGE_TIME )) { Fcb->Info.LastChangeTime = CurrentTime; SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_LAST_CHANGE ); SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO ); } if (UpdateLastModify) { // // Remember a change to a named data stream. // if (!FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA ) && (Scb->AttributeTypeCode == $DATA)) { SetFlag( ScbFlags, SCB_STATE_NOTIFY_MODIFY_STREAM ); } if (!FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_MOD_TIME )) { Fcb->Info.LastModificationTime = CurrentTime; SetFlag( Fcb->InfoFlags, FCB_INFO_CHANGED_LAST_MOD ); SetFlag( Fcb->FcbState, FCB_STATE_UPDATE_STD_INFO ); } } } if (UpdateLastAccess && !FlagOn( CcbFlags, CCB_FLAG_USER_SET_LAST_ACCESS_TIME ) && !FlagOn( NtfsData.Flags, NTFS_FLAGS_DISABLE_LAST_ACCESS )) { Fcb->CurrentLastAccess = CurrentTime; SetFlag( Fcb->InfoFlags, FCB_INFO_UPDATE_LAST_ACCESS ); } // // Clear all of the fast io flags in the file object. // ClearFlag( FileObject->Flags, FO_FILE_MODIFIED | FO_FILE_FAST_IO_READ ); } // // Now store the Scb flags into the Scb. // if (ScbFlags) { NtfsAcquireFsrtlHeader( Scb ); SetFlag( Scb->ScbState, ScbFlags ); NtfsReleaseFsrtlHeader( Scb ); } return; }
VOID FatFspClose ( IN PVCB Vcb OPTIONAL ) /*++ Routine Description: This routine implements the FSP part of Close. Arguments: Vcb - If present, tells us to only close file objects opened on the specified volume. Return Value: None. --*/ { PCLOSE_CONTEXT CloseContext; PVCB CurrentVcb = NULL; PVCB LastVcb = NULL; BOOLEAN FreeContext; ULONG LoopsWithVcbHeld; DebugTrace(+1, Dbg, "FatFspClose\n", 0); // // Set the top level IRP for the true FSP operation. // if (!ARGUMENT_PRESENT( Vcb )) { IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP ); } while (CloseContext = FatRemoveClose(Vcb, LastVcb)) { #ifdef __ND_FAT_SECONDARY__ NTSTATUS Status; #endif // // If we are in the FSP (i.e. Vcb == NULL), then try to keep ahead of // creates by doing several closes with one acquisition of the Vcb. // // Note that we cannot be holding the Vcb on entry to FatCommonClose // if this is last close as we will try to acquire FatData, and // worse the volume (and therefore the Vcb) may go away. // if (!ARGUMENT_PRESENT(Vcb)) { if (!FatData.ShutdownStarted) { if (CloseContext->Vcb != CurrentVcb) { LoopsWithVcbHeld = 0; // // Release a previously held Vcb, if any. // if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); } // // Get the new Vcb. // CurrentVcb = CloseContext->Vcb; (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE ); } else { // // Share the resource occasionally if we seem to be finding a lot // of closes for a single volume. // if (++LoopsWithVcbHeld >= 20) { if (ExGetSharedWaiterCount( &CurrentVcb->Resource ) + ExGetExclusiveWaiterCount( &CurrentVcb->Resource )) { ExReleaseResourceLite( &CurrentVcb->Resource); (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE ); } LoopsWithVcbHeld = 0; } } // // Now check the Open count. We may be about to delete this volume! // // The test below must be <= 1 because there could still be outstanding // stream references on this VCB that are not counted in the OpenFileCount. // For example if there are no open files OpenFileCount could be zero and we would // not release the resource here. The call to FatCommonClose() below may cause // the VCB to be torn down and we will try to release memory we don't // own later. // if (CurrentVcb->OpenFileCount <= 1) { ExReleaseResourceLite( &CurrentVcb->Resource); CurrentVcb = NULL; } // // If shutdown has started while processing our list, drop the // current Vcb resource. // } else if (CurrentVcb != NULL) { ExReleaseResourceLite( &CurrentVcb->Resource); CurrentVcb = NULL; } } LastVcb = CurrentVcb; // // Call the common Close routine. Protected in a try {} except {} // try { // // The close context either is in the CCB, automatically freed, // or was from pool for a metadata fileobject, CCB is NULL, and // we'll need to free it. // FreeContext = CloseContext->Free; #ifdef __ND_FAT_SECONDARY__ if (CloseContext->Fcb && FlagOn(CloseContext->Fcb->NdFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { PVOLUME_DEVICE_OBJECT VolumeDeviceObject = (CONTAINING_RECORD(CloseContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb)); BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN secondaryRecoveryResourceAcquired = FALSE; ASSERT( FreeContext == FALSE ); Status = STATUS_SUCCESS; while (TRUE) { ASSERT( secondaryRecoveryResourceAcquired == FALSE ); ASSERT( secondaryResourceAcquired == FALSE ); if (FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { if (FlagOn(VolumeDeviceObject->Vcb.NdFatFlags, ND_FAT_VCB_FLAG_TRY_CLOSE_FILES)) { Status = STATUS_CANT_WAIT; break; } secondaryRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( NULL, &VolumeDeviceObject->Secondary->RecoveryResource, TRUE ); if (!FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; continue; } secondaryResourceAcquired = SecondaryAcquireResourceExclusiveLite( NULL, &VolumeDeviceObject->Secondary->Resource, TRUE ); try { SessionRecovery( VolumeDeviceObject->Secondary, NULL ); } finally { SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->Resource ); secondaryResourceAcquired = FALSE; SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->RecoveryResource ); secondaryRecoveryResourceAcquired = FALSE; } continue; } secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( NULL, &VolumeDeviceObject->Secondary->Resource, TRUE ); if (secondaryResourceAcquired == FALSE) { ASSERT( FlagOn(VolumeDeviceObject->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(VolumeDeviceObject->Secondary->Flags, SECONDARY_FLAG_RECONNECTING) ); continue; } break; } if (Status == STATUS_SUCCESS) { try { Status = FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, NULL ); } finally { ASSERT( ExIsResourceAcquiredSharedLite(&VolumeDeviceObject->Secondary->Resource) ); SecondaryReleaseResourceLite( NULL, &VolumeDeviceObject->Secondary->Resource ); } } } else Status = FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, NULL ); #else (VOID)FatCommonClose( CloseContext->Vcb, CloseContext->Fcb, (FreeContext ? NULL : CONTAINING_RECORD( CloseContext, CCB, CloseContext)), CloseContext->TypeOfOpen, TRUE, NULL ); #endif } except(FatExceptionFilter( NULL, GetExceptionInformation() )) { // // Ignore anything we expect. // NOTHING; } // // Drop the context if it came from pool. // #ifdef __ND_FAT_SECONDARY__ if (Status == STATUS_CANT_WAIT) { ASSERT( FreeContext == FALSE ); ASSERT( CloseContext->Fcb && FlagOn(CloseContext->Fcb->FcbState, FCB_STATE_DELAY_CLOSE) ); FatQueueClose( CloseContext, (BOOLEAN)(CloseContext->Fcb && FlagOn(CloseContext->Fcb->FcbState, FCB_STATE_DELAY_CLOSE)) ); break; } if (FreeContext) { ExFreePool( CloseContext ); } #else if (FreeContext) { ExFreePool( CloseContext ); } #endif }