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 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; }
NTSTATUS AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; AFSDeviceExt *pDeviceExt = NULL; IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); AFSFcb *pFcb = NULL; AFSCcb *pCcb = NULL; PFILE_OBJECT pFileObject = NULL; AFSFcb *pRootFcb = NULL; AFSDeviceExt *pControlDeviceExt = NULL; IO_STATUS_BLOCK stIoSB; AFSObjectInfoCB *pObjectInfo = NULL; AFSFileCleanupCB stFileCleanup; ULONG ulNotificationFlags = 0; __try { if( AFSRDRDeviceObject == NULL) { // // Let this through, it's a cleanup on the library control device // try_return( ntStatus); } pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; // // Set some initial variables to make processing easier // pFileObject = pIrpSp->FileObject; pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; if( pFcb == NULL) { try_return( ntStatus); } pObjectInfo = pFcb->ObjectInformation; pRootFcb = pObjectInfo->VolumeCB->RootFcb; RtlZeroMemory( &stFileCleanup, sizeof( AFSFileCleanupCB)); stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); stFileCleanup.Identifier = (ULONGLONG)pFileObject; // // Perform the cleanup functionality depending on the type of node it is // switch( pFcb->Header.NodeTypeCode) { case AFS_ROOT_ALL: { AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); AFSReleaseResource( &pFcb->NPFcb->Resource); FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync, &pControlDeviceExt->Specific.Control.DirNotifyList, pCcb); break; } case AFS_IOCTL_FCB: { AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL && pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) { InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } // // This Fcb represents a file // case AFS_FILE_FCB: { // // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); // // If the handle has write permission ... // if( (pCcb->GrantedAccess & FILE_WRITE_DATA) && CcIsFileCached( pIrpSp->FileObject)) { __try { CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, NULL, 0, &stIoSB); if( !NT_SUCCESS( stIoSB.Status)) { AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", &pCcb->FullFileName, pObjectInfo->FileId.Cell, pObjectInfo->FileId.Volume, pObjectInfo->FileId.Vnode, pObjectInfo->FileId.Unique, stIoSB.Status, stIoSB.Information); ntStatus = stIoSB.Status; } } __except( EXCEPTION_EXECUTE_HANDLER) { ntStatus = GetExceptionCode(); } } // // Uninitialize the cache map. This call is unconditional. // AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n", pFcb, pFileObject); CcUninitializeCacheMap( pFileObject, NULL, NULL); // // Unlock all outstanding locks on the file, again, unconditionally // (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock, pFileObject, IoGetRequestorProcess( Irp), NULL); // // Tell the service to unlock all on the file // ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL; // // Perform some final common processing // ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); if( pFcb->ObjectInformation->ParentObjectInformation != NULL) { stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; } stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { stFileCleanup.AllocationSize = pObjectInfo->EndOfFile; stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) { stFileCleanup.CreateTime = pObjectInfo->CreationTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) { stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) { stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME)) { stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME); } } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME)) { stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime; } // // If the count has dropped to zero and there is a pending delete // then delete the node // if( pFcb->OpenHandleCount == 0 && BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { // // Stop anything possibly in process // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Specific.File.ExtentsResource, PsGetCurrentThread()); AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, TRUE); pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED; KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete, 0, FALSE); AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Specific.File.ExtentsResource, PsGetCurrentThread()); AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource); // // Before telling the server about the deleted file, tear down all extents for // the file // AFSTearDownFcbExtents( pFcb, &pCcb->AuthGroup); ntStatus = STATUS_SUCCESS; ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n", &pCcb->FullFileName, ntStatus); ntStatus = STATUS_SUCCESS; ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); } else { ntStatus = STATUS_SUCCESS; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n", &pCcb->FullFileName, pCcb->DirectoryCB); SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); ASSERT( pObjectInfo->ParentObjectInformation != NULL); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, (ULONG)FILE_ACTION_REMOVED); // // Now that the service has the entry has deleted we need to remove it from the parent // tree so another lookup on the node will fail // if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) { AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ removing entry\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, pCcb->DirectoryCB); AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); } } } else { if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { ULONG ulNotifyFilter = 0; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)ulNotifyFilter, (ULONG)FILE_ACTION_MODIFIED); } // // Attempt to flush any dirty extents to the server. This may be a little // aggressive, to flush whenever the handle is closed, but it ensures // coherency. // if( (pCcb->GrantedAccess & FILE_WRITE_DATA) && pFcb->Specific.File.ExtentsDirtyCount != 0) { AFSFlushExtents( pFcb, &pCcb->AuthGroup); } if( pFcb->OpenHandleCount == 0) { // // Wait for any outstanding queued flushes to complete // AFSWaitOnQueuedFlushes( pFcb); ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE; } // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); } // // Remove the share access at this time since we may not get the close for sometime on this FO. // IoRemoveShareAccess( pFileObject, &pFcb->ShareAccess); // // We don't need the name array after the user closes the handle on the file // if( pCcb->NameArray != NULL) { AFSFreeNameArray( pCcb->NameArray); pCcb->NameArray = NULL; } // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL) { ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } // // Root or directory node // case AFS_ROOT_FCB: { // // Set the root Fcb to this node // pRootFcb = pFcb; // // Fall through to below // } case AFS_DIRECTORY_FCB: { // // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); // // Perform some final common processing // ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); if( pFcb->ObjectInformation->ParentObjectInformation != NULL) { stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; } stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) { stFileCleanup.CreateTime = pObjectInfo->CreationTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) { stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) { stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); } } // // If the count has dropped to zero and there is a pending delete // then delete the node // if( pFcb->OpenHandleCount == 0 && BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { // // Try to notify the service about the delete // ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n", &pCcb->FullFileName, ntStatus); ntStatus = STATUS_SUCCESS; ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); } else { ntStatus = STATUS_SUCCESS; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n", &pCcb->FullFileName, pCcb->DirectoryCB); SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); ASSERT( pObjectInfo->ParentObjectInformation != NULL); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, (ULONG)FILE_ACTION_REMOVED); // // Now that the service has the entry has deleted we need to remove it from the parent // tree so another lookup on the node will fail // if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) { AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, pCcb->DirectoryCB); AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); } } } // // If there have been any updates to the node then push it to // the service // else { if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { ULONG ulNotifyFilter = 0; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); if( pObjectInfo->ParentObjectInformation != NULL) { ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)ulNotifyFilter, (ULONG)FILE_ACTION_MODIFIED); } } // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); } // // Release the notification for this directory if there is one // FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync, &pControlDeviceExt->Specific.Control.DirNotifyList, pCcb); // // Remove the share access at this time since we may not get the close for sometime on this FO. // IoRemoveShareAccess( pFileObject, &pFcb->ShareAccess); // // We don't need the name array after the user closes the handle on the file // if( pCcb->NameArray != NULL) { AFSFreeNameArray( pCcb->NameArray); pCcb->NameArray = NULL; } // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL) { ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } case AFS_SYMBOLIC_LINK_FCB: case AFS_MOUNT_POINT_FCB: case AFS_DFS_LINK_FCB: case AFS_INVALID_FCB: { // // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); // // Perform some final common processing // ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); if( pFcb->ObjectInformation->ParentObjectInformation != NULL) { stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; } stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) { stFileCleanup.CreateTime = pObjectInfo->CreationTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) { stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) { stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); } } // // If the count has dropped to zero and there is a pending delete // then delete the node // if( pFcb->OpenHandleCount == 0 && BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { // // Try to notify the service about the delete // ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n", &pCcb->FullFileName, ntStatus); ntStatus = STATUS_SUCCESS; ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); } else { ntStatus = STATUS_SUCCESS; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n", &pCcb->FullFileName, pCcb->DirectoryCB); SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); ASSERT( pObjectInfo->ParentObjectInformation != NULL); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, (ULONG)FILE_ACTION_REMOVED); // // Now that the service has the entry has deleted we need to remove it from the parent // tree so another lookup on the node will fail // if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) { AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, pCcb->DirectoryCB); AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); } } } // // If there have been any updates to the node then push it to // the service // else { if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { ULONG ulNotifyFilter = 0; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); if( pObjectInfo->ParentObjectInformation != NULL) { ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)ulNotifyFilter, (ULONG)FILE_ACTION_MODIFIED); } } // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); } // // Remove the share access at this time since we may not get the close for sometime on this FO. // IoRemoveShareAccess( pFileObject, &pFcb->ShareAccess); // // We don't need the name array after the user closes the handle on the file // if( pCcb->NameArray != NULL) { AFSFreeNameArray( pCcb->NameArray); pCcb->NameArray = NULL; } // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL) { ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } case AFS_SPECIAL_SHARE_FCB: { AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL && pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) { InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } default: AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_WARNING, "AFSCleanup Processing unknown node type %d\n", pFcb->Header.NodeTypeCode); break; } try_exit: if( pFileObject != NULL) { // // Setup the fileobject flags to indicate cleanup is complete. // SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE); } // // Complete the request // AFSCompleteRequest( Irp, ntStatus); }
__drv_mustHoldCriticalRegion NTSTATUS RfsdCleanup (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PRFSD_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PFILE_OBJECT FileObject; PRFSD_FCB Fcb = 0; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoAcquired = FALSE; PRFSD_CCB Ccb; PIRP Irp; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } VcbResourceAcquired = TRUE; FileObject = IrpContext->FileObject; Fcb = (PRFSD_FCB) FileObject->FsContext; if (!Fcb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (Fcb->Identifier.Type == RFSDVCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject) ) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; RfsdClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } Vcb->OpenHandleCount--; if (!Vcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); } Status = STATUS_SUCCESS; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == RFSDFCB) && (Fcb->Identifier.Size == sizeof(RFSD_FCB))); /* if ( !IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE)) */ { #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbResourceAcquired = TRUE; } Ccb = (PRFSD_CCB) FileObject->FsContext2; if (!Ccb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) { Status = RfsdFlushFile(Fcb); } _SEH2_LEAVE; } ASSERT((Ccb->Identifier.Type == RFSDCCB) && (Ccb->Identifier.Size == sizeof(RFSD_CCB))); Irp = IrpContext->Irp; Fcb->OpenHandleCount--; if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED )) { Fcb->NonCachedOpenCount--; } Vcb->OpenFileHandleCount--; if (IsFlagOn(Fcb->Flags, FCB_DELETE_ON_CLOSE)) { SetFlag(Fcb->Flags, FCB_DELETE_PENDING); if (IsDirectory(Fcb)) { FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Fcb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } } if (IsDirectory(Fcb)) { FsRtlNotifyCleanup( Vcb->NotifySync, &Vcb->NotifyList, Ccb ); } else { // // Drop any byte range locks this process may have on the file. // FsRtlFastUnlockAll( &Fcb->FileLockAnchor, FileObject, IoGetRequestorProcess(Irp), NULL ); // // If there are no byte range locks owned by other processes on the // file the fast I/O read/write functions doesn't have to check for // locks so we set IsFastIoPossible to FastIoIsPossible again. // if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) { if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) { RfsdPrint(( DBG_INFO, ": %-16.16s %-31s %s\n", RfsdGetCurrentProcessName(), "FastIoIsPossible", Fcb->AnsiFileName.Buffer )); Fcb->Header.IsFastIoPossible = FastIoIsPossible; } } } if ( IsFlagOn( FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedOpenCount != 0) && (Fcb->NonCachedOpenCount == Fcb->ReferenceCount) && (Fcb->SectionObject.DataSectionObject != NULL)) { if( !IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); } ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE); ExReleaseResourceLite(&(Fcb->PagingIoResource)); CcPurgeCacheSection( &Fcb->SectionObject, NULL, 0, FALSE ); } if (Fcb->OpenHandleCount == 0) { if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { // // Have to delete this file... // #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbPagingIoAcquired = TRUE; DbgBreak(); #if DISABLED Status = RfsdDeleteFile(IrpContext, Vcb, Fcb); if (NT_SUCCESS(Status)) { if (IsDirectory(Fcb)) { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED ); } else { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED ); } } #endif if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread() ); FcbPagingIoAcquired = FALSE; } } } if (!IsDirectory(Fcb) && FileObject->PrivateCacheMap) { RfsdPrint((DBG_INFO, "RfsdCleanup: CcUninitializeCacheMap is called for %s.\n", Fcb->AnsiFileName.Buffer )); CcUninitializeCacheMap( FileObject, (PLARGE_INTEGER)(&(Fcb->Header.FileSize)), NULL ); } if (!Fcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); } RfsdPrint((DBG_INFO, "RfsdCleanup: OpenCount: %u ReferCount: %u %s\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer )); Status = STATUS_SUCCESS; if (FileObject) { SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); } } _SEH2_FINALLY { if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread() ); } if (FcbResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread() ); } if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { RfsdQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; RfsdCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
NTSTATUS Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext) { PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; PUCHAR Buffer = NULL; LARGE_INTEGER ByteOffset; ULONG ReturnedLength = 0; ULONG Length; NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN Nocache = FALSE; BOOLEAN SynchronousIo = FALSE; BOOLEAN RecursiveWriteThrough = FALSE; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; BOOLEAN UpdateFileValidSize = FALSE; BOOLEAN FileSizesChanged = FALSE; BOOLEAN rc; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; Ccb = (PEXT2_CCB) FileObject->FsContext2; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } if (IsFileDeleted(Fcb->Mcb) || (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) { Status = STATUS_FILE_DELETED; __leave; } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && ByteOffset.HighPart == -1) { ByteOffset = FileObject->CurrentByteOffset; } else if (IsWritingToEof(ByteOffset)) { ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } if (Nocache && !PagingIo && ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) || (Length & (SECTOR_SIZE - 1))) ) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if ( !CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain ) ) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite( FileObject, (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite, IrpContext, Irp, Length, bAgain ); bDeferred = TRUE; Status = STATUS_PENDING; __leave; } } } if (IsDirectory(Fcb) && !PagingIo) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } if (IsFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && !IrpContext->IsTopLevel) { PIRP TopIrp; TopIrp = IoGetTopLevelIrp(); if ( (ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG && NodeType(TopIrp) == IO_TYPE_IRP) { PIO_STACK_LOCATION IrpStack; IrpStack = IoGetCurrentIrpStackLocation(TopIrp); if ((IrpStack->MajorFunction == IRP_MJ_WRITE) && (IrpStack->FileObject->FsContext == FileObject->FsContext) && !FlagOn(TopIrp->Flags, IRP_NOCACHE) ) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); RecursiveWriteThrough = TRUE; } } } if (PagingIo) { if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, TRUE)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; __leave; } else { ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } else { ReturnedLength = Length; } } else { if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) { Status = STATUS_ACCESS_DENIED; __leave; } if (IsDirectory(Fcb)) { __leave; } if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; // // Do flushing for such cases // if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject != NULL) { ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache( &(Fcb->SectionObject), &ByteOffset, CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE), &(Irp->IoStatus)); ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcPurgeCacheSection( &(Fcb->SectionObject), &(ByteOffset), CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE), FALSE ); } if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLockAnchor, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } if (Ccb != NULL) { Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, Ext2OplockComplete, Ext2LockIrp ); if (Status != STATUS_SUCCESS) { OpPostIrp = TRUE; __leave; } // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); } // // Extend the inode size when the i/o is beyond the file end ? // if ((ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) { LARGE_INTEGER AllocationSize, Last; if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); Last.QuadPart = Fcb->Header.AllocationSize.QuadPart; AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length); AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG, (ULONGLONG)AllocationSize.QuadPart, (ULONGLONG)BLOCK_SIZE); /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks for indirect files, otherwise we might get gabage data in holes */ IrpContext->MajorFunction += IRP_MJ_MAXIMUM_FUNCTION; Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize); IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION; if (AllocationSize.QuadPart > Last.QuadPart) { Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart; SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE); } ExReleaseResourceLite(&Fcb->PagingIoResource); PagingIoResourceAcquired = FALSE; if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { if (NT_SUCCESS(Status)) { DbgBreak(); Status = STATUS_UNSUCCESSFUL; } __leave; } if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } Fcb->Header.FileSize.QuadPart = Fcb->Inode->i_size = ByteOffset.QuadPart + Length; Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED; FileSizesChanged = TRUE; if (Fcb->Header.FileSize.QuadPart >= 0x80000000 && !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE); Ext2SaveSuper(IrpContext, Vcb); } DEBUG(DL_IO, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n", &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart)); } ReturnedLength = Length; } if (!Nocache) { if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &Ext2Global->CacheManagerCallbacks, Fcb ); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY ); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( FileObject, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); rc = Ext2ZeroData(IrpContext, Vcb, FileObject, &Fcb->Header.ValidDataLength, &ByteOffset); if (!rc) { Status = STATUS_PENDING; DbgBreak(); __leave; } } if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) { if (Ext2CanIWait() || !CcCopyWrite(FileObject, &ByteOffset, Length, TRUE, Buffer)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) { Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; } else { if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length) Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length; } CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); FileSizesChanged = TRUE; } Status = STATUS_SUCCESS; } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { DEBUG(DL_FLP, ("Ext2WriteFile is starting FlushingDpc...\n")); Ext2StartFloppyFlushDpc(Vcb, Fcb, FileObject); } } } else { if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); rc = Ext2ZeroData(IrpContext, Vcb, FileObject, &Fcb->Header.ValidDataLength, &ByteOffset); if (!rc) { Status = STATUS_PENDING; DbgBreak(); __leave; } } } Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = ReturnedLength; Status = Ext2WriteInode( IrpContext, Vcb, Fcb->Mcb, (ULONGLONG)(ByteOffset.QuadPart), NULL, ReturnedLength, TRUE, &Length ); Irp = IrpContext->Irp; if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { FileSizesChanged = TRUE; if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) { if (!PagingIo) Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length; Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; } else { if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length) Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length; } if (!PagingIo && CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } DEBUG(DL_IO, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n", &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart, ByteOffset.QuadPart, Length)); } } } if (FileSizesChanged) { FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED; Ext2NotifyReportChange( IrpContext, Vcb, Fcb->Mcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED ); } } __finally { /* * in case we got excpetions, we need revert MajorFunction * back to IRP_MJ_WRITE. The reason we do this, is to tell * Ext2ExpandFile to allocate unwritten extent or don't add * new blocks for indirect files. */ if (IrpContext->MajorFunction > IRP_MJ_MAXIMUM_FUNCTION) IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION; if (Irp) { if (PagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (MainResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } } if (!OpPostIrp && !IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT ) { if (!bDeferred) { Status = Ext2QueueRequest(IrpContext); } } else { if (NT_SUCCESS(Status) && !PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } SetFlag(FileObject->Flags, FO_FILE_MODIFIED); SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d " "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset, Length, PagingIo, Nocache, ReturnedLength, Fcb->Header.ValidDataLength.QuadPart,Fcb->Header.FileSize.QuadPart, Fcb->Inode->i_size, Status)); return Status; }
NTSTATUS Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PEXT2_VCB Vcb; PFILE_OBJECT FileObject; PEXT2_FCB Fcb; PEXT2_CCB Ccb; PIRP Irp; PEXT2_MCB Mcb; BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_SUCCESS; __leave; } Irp = IrpContext->Irp; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); if (!IsVcbInited(Vcb)) { Status = STATUS_SUCCESS; __leave; } FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; if (!Fcb || (Fcb->Identifier.Type != EXT2VCB && Fcb->Identifier.Type != EXT2FCB)) { Status = STATUS_SUCCESS; __leave; } Mcb = Fcb->Mcb; Ccb = (PEXT2_CCB) FileObject->FsContext2; if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { Status = STATUS_SUCCESS; __leave; } VcbResourceAcquired = ExAcquireResourceExclusiveLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (Fcb->Identifier.Type == EXT2VCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject) ) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } if (Ccb) { Ext2DerefXcb(&Vcb->OpenHandleCount); Ext2DerefXcb(&Vcb->OpenVolumeCount); } IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); Status = STATUS_SUCCESS; __leave; } ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) { Status = Ext2FlushFile(IrpContext, Fcb, Ccb); } __leave; } if (Ccb == NULL) { Status = STATUS_SUCCESS; __leave; } if (IsDirectory(Fcb)) { if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Ccb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb); } ExReleaseResourceLite(&Vcb->MainResource); VcbResourceAcquired = FALSE; FcbResourceAcquired = ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); ASSERT((Ccb->Identifier.Type == EXT2CCB) && (Ccb->Identifier.Size == sizeof(EXT2_CCB))); Ext2DerefXcb(&Vcb->OpenHandleCount); Ext2DerefXcb(&Fcb->OpenHandleCount); if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE; } if (IsDirectory(Fcb)) { ext3_release_dir(Fcb->Inode, &Ccb->filp); } else { if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) { LARGE_INTEGER SysTime; KeQuerySystemTime(&SysTime); Fcb->Inode->i_atime = Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime); Fcb->Mcb->LastAccessTime = Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime); Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); Ext2NotifyReportChange( IrpContext, Vcb, Fcb->Mcb, FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS, FILE_ACTION_MODIFIED ); } FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, NULL, NULL ); Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { Fcb->NonCachedOpenCount--; } if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); } // // Drop any byte range locks this process may have on the file. // FsRtlFastUnlockAll( &Fcb->FileLockAnchor, FileObject, IoGetRequestorProcess(Irp), NULL ); // // If there are no byte range locks owned by other processes on the // file the fast I/O read/write functions doesn't have to check for // locks so we set IsFastIoPossible to FastIoIsPossible again. // if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) { if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) { #if EXT2_DEBUG DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n", Ext2GetCurrentProcessName(), "FastIoIsPossible", &Fcb->Mcb->FullName )); #endif Fcb->Header.IsFastIoPossible = FastIoIsPossible; } } if (Fcb->OpenHandleCount == 0 && (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE) || IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) ) { LARGE_INTEGER Size; ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE); FcbPagingIoResourceAcquired = TRUE; Size.QuadPart = CEILING_ALIGNED(ULONGLONG, (ULONGLONG)Fcb->Mcb->Inode.i_size, (ULONGLONG)BLOCK_SIZE); if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size); Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart = Fcb->Mcb->Inode.i_size; Fcb->Header.AllocationSize = Size; if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } } ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE); ExReleaseResourceLite(&Fcb->PagingIoResource); FcbPagingIoResourceAcquired = FALSE; } } if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) { // // Ext2DeleteFile will acquire these lock inside // if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); FcbResourceAcquired = FALSE; } // // this file is to be deleted ... // if (Ccb->SymLink) { Mcb = Ccb->SymLink; FileObject->DeletePending = FALSE; } Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); if (NT_SUCCESS(Status)) { if (IsMcbDirectory(Mcb)) { Ext2NotifyReportChange( IrpContext, Vcb, Mcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED ); } else { Ext2NotifyReportChange( IrpContext, Vcb, Mcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED ); } } // // re-acquire the main resource lock // FcbResourceAcquired = ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } } if (!IsDirectory(Fcb)) { if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) && (Fcb->SectionObject.DataSectionObject != NULL)) { if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) { CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); } if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) { ExReleaseResourceLite(&(Fcb->PagingIoResource)); } CcPurgeCacheSection( &Fcb->SectionObject, NULL, 0, FALSE ); } CcUninitializeCacheMap(FileObject, NULL, NULL); } IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName)); Status = STATUS_SUCCESS; if (FileObject) { SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); } } __finally { if (FcbPagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; Ext2CompleteIrpContext(IrpContext, 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; }
/* Last handle to a file object is closed */ NTSTATUS NTAPI FatiCleanup(PFAT_IRP_CONTEXT IrpContext, PIRP Irp) { PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PSHARE_ACCESS ShareAccess; BOOLEAN SendUnlockNotification = FALSE; PLARGE_INTEGER TruncateSize = NULL; //LARGE_INTEGER LocalTruncateSize; BOOLEAN AcquiredVcb = FALSE, AcquiredFcb = FALSE; NTSTATUS Status; PVCB Vcb; PFCB Fcb; PCCB Ccb; IrpSp = IoGetCurrentIrpStackLocation( Irp ); DPRINT("FatiCleanup\n"); DPRINT("\tIrp = %p\n", Irp); DPRINT("\t->FileObject = %p\n", IrpSp->FileObject); FileObject = IrpSp->FileObject; TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb); if (TypeOfOpen == UnopenedFileObject) { DPRINT1("Unopened File Object\n"); FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); return STATUS_SUCCESS; } if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) { /* Just flush the file */ if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) && FlagOn(FileObject->Flags, FO_FILE_MODIFIED) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED) && (TypeOfOpen == UserFileOpen)) { //Status = FatFlushFile(IrpContext, Fcb, Flush); //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status); UNIMPLEMENTED; } FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); return STATUS_SUCCESS; } if (TypeOfOpen == UserFileOpen || TypeOfOpen == UserDirectoryOpen) { ASSERT(Fcb != NULL); (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); AcquiredFcb = TRUE; /* Set FCB flags according to DELETE_ON_CLOSE */ if (FlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { ASSERT(FatNodeType(Fcb) != FAT_NTC_ROOT_DCB); SetFlag(Fcb->State, FCB_STATE_DELETE_ON_CLOSE); /* Issue a notification */ if (TypeOfOpen == UserDirectoryOpen) { FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->NotifyList, FileObject->FsContext, NULL, FALSE, FALSE, 0, NULL, NULL, NULL); } } /* If file should be deleted, acquire locks */ if ((Fcb->UncleanCount == 1) && FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && (Fcb->Condition != FcbBad) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { FatReleaseFcb(IrpContext, Fcb); AcquiredFcb = FALSE; (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb); AcquiredVcb = TRUE; (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); AcquiredFcb = TRUE; } } /* Acquire VCB lock if it was a volume open */ if (TypeOfOpen == UserVolumeOpen) { (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb); AcquiredVcb = TRUE; } /* Cleanup all notifications */ if (TypeOfOpen == UserDirectoryOpen) { FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb); } if (Fcb) { //TODO: FatVerifyFcb } switch (TypeOfOpen) { case DirectoryFile: case VirtualVolumeFile: DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n"); ShareAccess = NULL; break; case UserVolumeOpen: DPRINT("Cleanup UserVolumeOpen\n"); if (FlagOn(Ccb->Flags, CCB_COMPLETE_DISMOUNT)) { FatCheckForDismount( IrpContext, Vcb, TRUE ); } else if (FileObject->WriteAccess && FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { UNIMPLEMENTED; } /* Release the volume and send notification */ if (FlagOn(Vcb->State, VCB_STATE_FLAG_LOCKED) && (Vcb->FileObjectWithVcbLocked == FileObject)) { UNIMPLEMENTED; SendUnlockNotification = TRUE; } ShareAccess = &Vcb->ShareAccess; break; case EaFile: DPRINT1("Cleanup EaFileObject\n"); ShareAccess = NULL; break; case UserDirectoryOpen: DPRINT("Cleanup UserDirectoryOpen\n"); ShareAccess = &Fcb->ShareAccess; /* Should it be a delayed close? */ if ((Fcb->UncleanCount == 1) && (Fcb->OpenCount == 1) && (Fcb->Dcb.DirectoryFileOpenCount == 0) && !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && Fcb->Condition == FcbGood) { /* Yes, a delayed one */ SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); } if (VcbGood == Vcb->Condition) { //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); //TODO: Actually update dirent } if ((Fcb->UncleanCount == 1) && (FatNodeType(Fcb) == FAT_NTC_DCB) && (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) && (Fcb->Condition != FcbBad) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { UNIMPLEMENTED; } /* Decrement unclean counter */ ASSERT(Fcb->UncleanCount != 0); Fcb->UncleanCount--; break; case UserFileOpen: DPRINT("Cleanup UserFileOpen\n"); ShareAccess = &Fcb->ShareAccess; /* Should it be a delayed close? */ if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) && (FileObject->SectionObjectPointer->ImageSectionObject == NULL) && (Fcb->UncleanCount == 1) && (Fcb->OpenCount == 1) && !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && Fcb->Condition == FcbGood) { /* Yes, a delayed one */ //SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb, Fcb->FatHandle, &Fcb->FullFileName); } /* Unlock all file locks */ FsRtlFastUnlockAll(&Fcb->Fcb.Lock, FileObject, IoGetRequestorProcess(Irp), NULL); if (Vcb->Condition == VcbGood) { if (Fcb->Condition != FcbBad) { //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); // TODO: Update on-disk structures } if (Fcb->UncleanCount == 1 && Fcb->Condition != FcbBad) { //DELETE_CONTEXT DeleteContext; /* Should this file be deleted on close? */ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { UNIMPLEMENTED; } else { if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) && (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart)) { #if 0 ULONG ValidDataLength; ValidDataLength = Fcb->Header.ValidDataLength.LowPart; if (ValidDataLength < Fcb->ValidDataToDisk) { ValidDataLength = Fcb->ValidDataToDisk; } if (ValidDataLength < Fcb->Header.FileSize.LowPart) { FatZeroData( IrpContext, Vcb, FileObject, ValidDataLength, Fcb->Header.FileSize.LowPart - ValidDataLength ); Fcb->ValidDataToDisk = Fcb->Header.ValidDataLength.LowPart = Fcb->Header.FileSize.LowPart; if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); } } #endif DPRINT1("Zeroing out data is not implemented\n"); } } /* Should the file be truncated on close? */ if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE)) { if (Vcb->Condition == VcbGood) { // TODO: Actually truncate the file allocation UNIMPLEMENTED; } /* Remove truncation flag */ Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE; } /* Check again if it should be deleted */ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && Fcb->Header.AllocationSize.LowPart == 0) { FatNotifyReportChange(IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED); } /* Remove the entry from the splay table if the file was deleted */ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) { FatRemoveNames(IrpContext, Fcb); } } } ASSERT(Fcb->UncleanCount != 0); Fcb->UncleanCount--; if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { ASSERT(Fcb->NonCachedUncleanCount != 0); Fcb->NonCachedUncleanCount--; } if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedUncleanCount != 0) && (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) && (Fcb->SectionObjectPointers.DataSectionObject != NULL)) { CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL); /* Acquire and release PagingIo to get in sync with lazy writer */ ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE); ExReleaseResourceLite(Fcb->Header.PagingIoResource); CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE); } if (Fcb->Condition == FcbBad) { //TruncateSize = &FatLargeZero; UNIMPLEMENTED; } /* Cleanup the cache map */ CcUninitializeCacheMap(FileObject, TruncateSize, NULL); break; default: KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0); } /* Cleanup the share access */ if (ShareAccess) { DPRINT("Cleaning up the share access\n"); IoRemoveShareAccess(FileObject, ShareAccess); } if (TypeOfOpen == UserFileOpen) { /* Update oplocks */ FsRtlCheckOplock(&Fcb->Fcb.Oplock, Irp, IrpContext, NULL, NULL); Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb); } /* Set the FO_CLEANUP_COMPLETE flag */ SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); Status = STATUS_SUCCESS; // TODO: Unpin repinned BCBs //FatUnpinRepinnedBcbs(IrpContext); /* Flush the volume if necessary */ if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { UNIMPLEMENTED; } /* Cleanup */ if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb); if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb); /* Send volume notification */ if (SendUnlockNotification) FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); return Status; }