NTSTATUS FatPostStackOverflowRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PFCB Fcb ) /*++ Routine Description: This routine posts a read request that could not be processed by the fsp thread because of stack overflow potential. Arguments: Irp - Supplies the request to process. Fcb - Supplies the file. Return Value: STATUS_PENDING. --*/ { KEVENT Event; PERESOURCE Resource; PVCB Vcb; PAGED_CODE(); DebugTrace(0, Dbg, "Getting too close to stack limit pass request to Fsp\n", 0 ); // // Initialize an event and get shared on the resource we will // be later using the common read. // KeInitializeEvent( &Event, NotificationEvent, FALSE ); // // Preacquire the resource the read path will require so we know the // worker thread can proceed without waiting. // if (FlagOn(Irp->Flags, IRP_PAGING_IO) && (Fcb->Header.PagingIoResource != NULL)) { Resource = Fcb->Header.PagingIoResource; } else { Resource = Fcb->Header.Resource; } // // If there are no resources assodicated with the file (case: the virtual // volume file), it is OK. No resources will be acquired on the other side // as well. // if (Resource) { ExAcquireResourceSharedLite( Resource, TRUE ); } if (NodeType( Fcb ) == FAT_NTC_VCB) { Vcb = (PVCB) Fcb; } else { Vcb = Fcb->Vcb; } try { // // Make the Irp just like a regular post request and // then send the Irp to the special overflow thread. // After the post we will wait for the stack overflow // read routine to set the event that indicates we can // now release the scb resource and return. // FatPrePostIrp( IrpContext, Irp ); // // If this read is the result of a verify, we have to // tell the overflow read routne to temporarily // hijack the Vcb->VerifyThread field so that reads // can go through. // if (Vcb->VerifyThread == KeGetCurrentThread()) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ); } FsRtlPostStackOverflow( IrpContext, &Event, FatStackOverflowRead ); // // And wait for the worker thread to complete the item // KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); } finally { if (Resource) { ExReleaseResourceLite( Resource ); } } return STATUS_PENDING; }
VOID FatStackOverflowRead ( IN PVOID Context, IN PKEVENT Event ) /*++ Routine Description: This routine processes a read request that could not be processed by the fsp thread because of stack overflow potential. Arguments: Context - Supplies the IrpContext being processed Event - Supplies the event to be signaled when we are done processing this request. Return Value: None. --*/ { PIRP_CONTEXT IrpContext = Context; PKTHREAD SavedVerifyThread = NULL; PVCB Vcb = NULL; PAGED_CODE(); // // Make it now look like we can wait for I/O to complete // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); // // If this read was as the result of a verify we have to fake out the // the Vcb->VerifyThread field. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { PFCB Fcb = (PFCB)IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)-> FileObject->FsContext; if (NodeType( Fcb ) == FAT_NTC_VCB) { Vcb = (PVCB) Fcb; } else { Vcb = Fcb->Vcb; } NT_ASSERT( Vcb->VerifyThread != NULL ); SavedVerifyThread = Vcb->VerifyThread; Vcb->VerifyThread = KeGetCurrentThread(); } // // Do the read operation protected by a try-except clause // try { (VOID) FatCommonRead( IrpContext, IrpContext->OriginatingIrp ); } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { NTSTATUS ExceptionCode; // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // ExceptionCode = GetExceptionCode(); if (ExceptionCode == STATUS_FILE_DELETED) { IrpContext->ExceptionStatus = ExceptionCode = STATUS_END_OF_FILE; IrpContext->OriginatingIrp->IoStatus.Information = 0; } (VOID) FatProcessException( IrpContext, IrpContext->OriginatingIrp, ExceptionCode ); } // // Restore the original VerifyVolumeThread // if (SavedVerifyThread != NULL) { NT_ASSERT( Vcb->VerifyThread == KeGetCurrentThread() ); Vcb->VerifyThread = SavedVerifyThread; } // // Set the stack overflow item's event to tell the original // thread that we're done. // KeSetEvent( Event, 0, FALSE ); }
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)) { 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 (Nocache && ( (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 (IsWritingToEof(ByteOffset)) { ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } 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.AllocationSize.QuadPart) { if ( ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_END_OF_FILE; Irp->IoStatus.Information = 0; __leave; } else { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } } else { 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 + Length > Fcb->Header.ValidDataLength.QuadPart ) { 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) && !PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { FileSizesChanged = TRUE; 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; } if (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, if 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 FatFsdRead ( _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, _Inout_ PIRP Irp ) /*++ Routine Description: This is the driver entry to the common read routine for NtReadFile calls. For synchronous requests, the CommonRead is called with Wait == TRUE, which means the request will always be completed in the current thread, and never passed to the Fsp. If it is not a synchronous request, CommonRead is called with Wait == FALSE, which means the request will be passed to the Fsp only if there is a need to block. Arguments: VolumeDeviceObject - Supplies the volume device object where the file being Read exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { PFCB Fcb = NULL; NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; BOOLEAN TopLevel = FALSE; DebugTrace(+1, Dbg, "FatFsdRead\n", 0); // // Call the common Read routine, with blocking allowed if synchronous // FsRtlEnterFileSystem(); // // We are first going to do a quick check for paging file IO. Since this // is a fast path, we must replicate the check for the fsdo. // if (!FatDeviceIsFatFsdo( IoGetCurrentIrpStackLocation(Irp)->DeviceObject)) { Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext); if ((NodeType(Fcb) == FAT_NTC_FCB) && FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) { // // Do the usual STATUS_PENDING things. // IoMarkIrpPending( Irp ); // // If there is not enough stack to do this read, then post this // read to the overflow queue. // if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) { KEVENT Event; PAGING_FILE_OVERFLOW_PACKET Packet; Packet.Irp = Irp; Packet.Fcb = Fcb; KeInitializeEvent( &Event, NotificationEvent, FALSE ); FsRtlPostPagingFileStackOverflow( &Packet, &Event, FatOverflowPagingFileRead ); // // And wait for the worker thread to complete the item // (VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); } else { // // Perform the actual IO, it will be completed when the io finishes. // FatPagingFileIo( Irp, Fcb ); } FsRtlExitFileSystem(); return STATUS_PENDING; } } try { TopLevel = FatIsIrpTopLevel( Irp ); IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) ); // // If this is an Mdl complete request, don't go through // common read. // if ( FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE) ) { DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 ); try_return( Status = FatCompleteMdl( IrpContext, Irp )); } // // Check if we have enough stack space to process this request. If there // isn't enough then we will pass the request off to the stack overflow thread. // if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) { DebugTrace(0, Dbg, "Passing StackOverflowRead off\n", 0 ); try_return( Status = FatPostStackOverflowRead( IrpContext, Irp, Fcb ) ); } Status = FatCommonRead( IrpContext, Irp ); try_exit: NOTHING; } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } if (TopLevel) { IoSetTopLevelIrp( NULL ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace(-1, Dbg, "FatFsdRead -> %08lx\n", Status); UNREFERENCED_PARAMETER( VolumeDeviceObject ); return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FatCommonPnp ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing PnP operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PVOLUME_DEVICE_OBJECT OurDeviceObject; PVCB Vcb; PAGED_CODE(); // // Force everything to wait. // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); // // Get the current Irp stack location. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); // // Find our Vcb. This is tricky since we have no file object in the Irp. // OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject; // // Take the global lock to synchronise against volume teardown. // #pragma prefast( push ) #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" ) #pragma prefast( disable: 28193, "this will always wait" ) FatAcquireExclusiveGlobal( IrpContext ); #pragma prefast( pop ) // // Make sure this device object really is big enough to be a volume device // object. If it isn't, we need to get out before we try to reference some // field that takes us past the end of an ordinary device object. // #pragma prefast( suppress: 28175, "touching Size is ok for a filesystem" ) if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) || NodeType( &OurDeviceObject->Vcb ) != FAT_NTC_VCB) { // // We were called with something we don't understand. // FatReleaseGlobal( IrpContext ); Status = STATUS_INVALID_PARAMETER; FatCompleteRequest( IrpContext, Irp, Status ); return Status; } Vcb = &OurDeviceObject->Vcb; // // Case on the minor code. // switch ( IrpSp->MinorFunction ) { case IRP_MN_QUERY_REMOVE_DEVICE: Status = FatPnpQueryRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_SURPRISE_REMOVAL: Status = FatPnpSurpriseRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_REMOVE_DEVICE: Status = FatPnpRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_CANCEL_REMOVE_DEVICE: Status = FatPnpCancelRemove( IrpContext, Irp, Vcb ); break; default: FatReleaseGlobal( IrpContext ); // // Just pass the IRP on. As we do not need to be in the // way on return, ellide ourselves out of the stack. // IoSkipCurrentIrpStackLocation( Irp ); Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); // // Cleanup our Irp Context. The driver has completed the Irp. // FatCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); break; } return Status; }
NTSTATUS FatCommonPnp ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing PnP operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PVOLUME_DEVICE_OBJECT OurDeviceObject; PVCB Vcb; // // Get the current Irp stack location. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); // // Find our Vcb. This is tricky since we have no file object in the Irp. // OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject; // // Make sure this device object really is big enough to be a volume device // object. If it isn't, we need to get out before we try to reference some // field that takes us past the end of an ordinary device object. // if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) || NodeType( &OurDeviceObject->Vcb ) != FAT_NTC_VCB) { // // We were called with something we don't understand. // Status = STATUS_INVALID_PARAMETER; FatCompleteRequest( IrpContext, Irp, Status ); return Status; } // // Force everything to wait. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); Vcb = &OurDeviceObject->Vcb; #ifdef __ND_FAT_SECONDARY__ if( ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Secondary && ( ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode == NETDISK_SECONDARY || ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY ) ) { PSECONDARY Secondary = ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Secondary; Status = STATUS_SUCCESS; Secondary_Reference( Secondary ); switch ( IrpSp->MinorFunction ) { case IRP_MN_QUERY_REMOVE_DEVICE: { DebugTrace2( 0, Dbg, ("FatCommonPnp: IRP_MN_QUERY_REMOVE_DEVICE NetdiskEnableMode = %d\n", ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode) ); ExAcquireFastMutex( &Secondary->FastMutex ); if (!Secondary->TryCloseActive) { Secondary->TryCloseActive = TRUE; ExReleaseFastMutex( &Secondary->FastMutex ); Secondary_Reference( Secondary ); //FatDebugTraceLevel |= DEBUG_TRACE_CLOSE; SecondaryTryClose( IrpContext, Secondary ); //FatDebugTraceLevel &= ~DEBUG_TRACE_CLOSE; } else { ExReleaseFastMutex( &Secondary->FastMutex ); } if(Vcb->SecondaryOpenFileCount) { LARGE_INTEGER interval; // Wait all files closed interval.QuadPart = (1 * HZ); //delay 1 seconds KeDelayExecutionThread(KernelMode, FALSE, &interval); } #if 0 if (Vcb->SecondaryOpenFileCount) { LONG ccbCount; PLIST_ENTRY ccbListEntry; PVOID restartKey; PFCB fcb; ExAcquireFastMutex( &Secondary->RecoveryCcbQMutex ); for (ccbCount = 0, ccbListEntry = Secondary->RecoveryCcbQueue.Flink; ccbListEntry != &Secondary->RecoveryCcbQueue; ccbListEntry = ccbListEntry->Flink, ccbCount++); ExReleaseFastMutex( &Secondary->RecoveryCcbQMutex ); ASSERT( !IsListEmpty(&Secondary->RecoveryCcbQueue) ); ASSERT( ccbCount == Vcb->SecondaryOpenFileCount ); DebugTrace2( 0, Dbg, ("IRP_MN_QUERY_REMOVE_DEVICE: Vcb->SecondaryCloseCount = %d, Vcb->CloseCount = %d, ccbCount = %d\n", Vcb->SecondaryOpenFileCount, Vcb->OpenCount, ccbCount) ); restartKey = NULL; fcb = NdFatGetNextFcbTableEntry( &Secondary->VolDo->Vcb, &restartKey ); ASSERT( fcb != NULL || !IsListEmpty(&Secondary->DeletedFcbQueue) ); Status = STATUS_UNSUCCESSFUL; } #endif break; } case IRP_MN_REMOVE_DEVICE: { PVOID restartKey; PFCB fcb; DebugTrace2( 0, Dbg, ("FatCommonPnp: IRP_MN_REMOVE_DEVICE NetdiskEnableMode = %d\n", ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode) ); #if 0 restartKey = NULL; fcb = NdFatGetNextFcbTableEntry( &Secondary->VolDo->Vcb, &restartKey ); ASSERT( fcb == NULL && IsListEmpty(&Secondary->DeletedFcbQueue) ); #endif if(Vcb->SecondaryOpenFileCount) { ASSERT( NDFAT_BUG ); Status = STATUS_UNSUCCESSFUL; } break; } default: { DebugTrace2( 0, Dbg, ("FatCommonPnp: IrpSp-MinorFunction = %d NetdiskEnableMode = %d\n", IrpSp->MinorFunction, ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode) ); if(IrpSp->FileObject && IS_SECONDARY_FILEOBJECT(IrpSp->FileObject)) { ASSERT( FALSE ); Status = STATUS_UNSUCCESSFUL; } break; } } Secondary_Dereference( Secondary ); if (!NT_SUCCESS(Status)) { FatCompleteRequest( NULL, Irp, Status ); return Status; } } #endif // // Case on the minor code. // switch ( IrpSp->MinorFunction ) { case IRP_MN_QUERY_REMOVE_DEVICE: Status = FatPnpQueryRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_SURPRISE_REMOVAL: Status = FatPnpSurpriseRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_REMOVE_DEVICE: Status = FatPnpRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_CANCEL_REMOVE_DEVICE: Status = FatPnpCancelRemove( IrpContext, Irp, Vcb ); break; default: // // Just pass the IRP on. As we do not need to be in the // way on return, ellide ourselves out of the stack. // IoSkipCurrentIrpStackLocation( Irp ); Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); // // Cleanup our Irp Context. The driver has completed the Irp. // FatCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); break; } return Status; }
__drv_mustHoldCriticalRegion NTSTATUS FatProcessException ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN NTSTATUS ExceptionCode ) /*++ Routine Description: This routine process an exception. It either completes the request with the saved exception status or it sends it off to IoRaiseHardError() Arguments: Irp - Supplies the Irp being processed ExceptionCode - Supplies the normalized exception status being handled Return Value: NTSTATUS - Returns the results of either posting the Irp or the saved completion status. --*/ { PVCB Vcb; PIO_STACK_LOCATION IrpSp; FAT_VOLUME_STATE TransitionState = VolumeDirty; ULONG SavedFlags = 0; PAGED_CODE(); DebugTrace(0, Dbg, "FatProcessException\n", 0); // // If there is not an irp context, we must have had insufficient resources. // if ( !ARGUMENT_PRESENT( IrpContext ) ) { FatCompleteRequest( FatNull, Irp, ExceptionCode ); return ExceptionCode; } // // Get the real exception status from IrpContext->ExceptionStatus, and // reset it. // ExceptionCode = IrpContext->ExceptionStatus; FatResetExceptionState( IrpContext ); // // If this is an Mdl write request, then take care of the Mdl // here so that things get cleaned up properly. Cc now leaves // the MDL in place so a filesystem can retry after clearing an // internal condition (FAT does not). // if ((IrpContext->MajorFunction == IRP_MJ_WRITE) && (FlagOn( IrpContext->MinorFunction, IRP_MN_COMPLETE_MDL ) == IRP_MN_COMPLETE_MDL) && (Irp->MdlAddress != NULL)) { PIO_STACK_LOCATION LocalIrpSp = IoGetCurrentIrpStackLocation(Irp); CcMdlWriteAbort( LocalIrpSp->FileObject, Irp->MdlAddress ); Irp->MdlAddress = NULL; } // // If we are going to post the request, we may have to lock down the // user's buffer, so do it here in a try except so that we failed the // request if the LockPages fails. // // Also unpin any repinned Bcbs, protected by the try {} except {} filter. // try { SavedFlags = IrpContext->Flags; // // Make sure we don't try to write through Bcbs // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH); FatUnpinRepinnedBcbs( IrpContext ); IrpContext->Flags = SavedFlags; // // If we will have to post the request, do it here. Note // that the last thing FatPrePostIrp() does is mark the Irp pending, // so it is critical that we actually return PENDING. Nothing // from this point to return can fail, so we are OK. // // We cannot do a verify operations at APC level because we // have to wait for Io operations to complete. // if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) && (((ExceptionCode == STATUS_VERIFY_REQUIRED) && KeAreAllApcsDisabled()) || (ExceptionCode == STATUS_CANT_WAIT))) { ExceptionCode = FatFsdPostRequest( IrpContext, Irp ); } } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) { ExceptionCode = IrpContext->ExceptionStatus; IrpContext->ExceptionStatus = 0; IrpContext->Flags = SavedFlags; } // // If we posted the request, just return here. // if (ExceptionCode == STATUS_PENDING) { return ExceptionCode; } Irp->IoStatus.Status = ExceptionCode; // // If this request is not a "top-level" irp, just complete it. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) { // // If there is a cache operation above us, commute verify // to a lock conflict. This will cause retries so that // we have a chance of getting through without needing // to return an unaesthetic error for the operation. // if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP && ExceptionCode == STATUS_VERIFY_REQUIRED) { ExceptionCode = STATUS_FILE_LOCK_CONFLICT; } FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } if (IoIsErrorUserInduced(ExceptionCode)) { // // Check for the various error conditions that can be caused by, // and possibly resolved by the user. // if (ExceptionCode == STATUS_VERIFY_REQUIRED) { PDEVICE_OBJECT Device; DebugTrace(0, Dbg, "Perform Verify Operation\n", 0); // // Now we are at the top level file system entry point. // // Grab the device to verify from the thread local storage // and stick it in the information field for transportation // to the fsp. We also clear the field at this time. // Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread ); IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL ); if ( Device == NULL ) { Device = IoGetDeviceToVerify( PsGetCurrentThread() ); IoSetDeviceToVerify( PsGetCurrentThread(), NULL ); ASSERT( Device != NULL ); } // // Let's not BugCheck just because the driver messed up. // if (Device == NULL) { ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR; FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } // // FatPerformVerify() will do the right thing with the Irp. return FatPerformVerify( IrpContext, Irp, Device ); } // // The other user induced conditions generate an error unless // they have been disabled for this request. // if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS)) { FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } else { // // Generate a pop-up // PDEVICE_OBJECT RealDevice; PVPB Vpb; PETHREAD Thread; if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL) { Vpb = IoGetCurrentIrpStackLocation(Irp)->FileObject->Vpb; } else { Vpb = NULL; } // // The device to verify is either in my thread local storage // or that of the thread that owns the Irp. // Thread = Irp->Tail.Overlay.Thread; RealDevice = IoGetDeviceToVerify( Thread ); if ( RealDevice == NULL ) { Thread = PsGetCurrentThread(); RealDevice = IoGetDeviceToVerify( Thread ); ASSERT( RealDevice != NULL ); } // // Let's not BugCheck just because the driver messed up. // if (RealDevice == NULL) { FatCompleteRequest( IrpContext, Irp, ExceptionCode ); return ExceptionCode; } // // This routine actually causes the pop-up. It usually // does this by queuing an APC to the callers thread, // but in some cases it will complete the request immediately, // so it is very important to IoMarkIrpPending() first. // IoMarkIrpPending( Irp ); IoRaiseHardError( Irp, Vpb, RealDevice ); // // We will be handing control back to the caller here, so // reset the saved device object. // IoSetDeviceToVerify( Thread, NULL ); // // The Irp will be completed by Io or resubmitted. In either // case we must clean up the IrpContext here. // FatDeleteIrpContext( IrpContext ); return STATUS_PENDING; } } // // This is just a run of the mill error. If is a STATUS that we // raised ourselves, and the information would be use for the // user, raise an informational pop-up. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); Vcb = IrpContext->Vcb; // // Now, if the Vcb is unknown to us this means that the error was raised // in the process of a mount and before we even had a chance to build // a full Vcb - and was really handled there. // if (Vcb != NULL) { if ( !FatDeviceIsFatFsdo( IrpSp->DeviceObject) && !NT_SUCCESS(ExceptionCode) && !FsRtlIsTotalDeviceFailure(ExceptionCode) ) { TransitionState = VolumeDirtyWithSurfaceTest; } // // If this was a STATUS_FILE_CORRUPT or similar error indicating some // nastiness out on the media, then mark the volume permanently dirty. // if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS) && ( TransitionState == VolumeDirtyWithSurfaceTest || (ExceptionCode == STATUS_FILE_CORRUPT_ERROR) || (ExceptionCode == STATUS_DISK_CORRUPT_ERROR) || (ExceptionCode == STATUS_EA_CORRUPT_ERROR) || (ExceptionCode == STATUS_INVALID_EA_NAME) || (ExceptionCode == STATUS_EA_LIST_INCONSISTENT) || (ExceptionCode == STATUS_NO_EAS_ON_FILE) )) { ASSERT( NodeType(Vcb) == FAT_NTC_VCB ); ASSERT( !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)); SetFlag( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ); SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); // // Do the "dirty" work, ignoring any error. We need to take the Vcb here // to synchronize against the verify path tearing things down, since // we dropped all synchronization when backing up due to the exception. // FatAcquireExclusiveVcbNoOpCheck( IrpContext, Vcb); try { if (VcbGood == Vcb->VcbCondition) { FatMarkVolume( IrpContext, Vcb, TransitionState ); } } except( FatExceptionFilter( IrpContext, GetExceptionInformation() ) ) { NOTHING; } FatReleaseVcb( IrpContext, Vcb); } }
nsresult CharacterData::SetTextInternal(uint32_t aOffset, uint32_t aCount, const char16_t* aBuffer, uint32_t aLength, bool aNotify, CharacterDataChangeInfo::Details* aDetails) { MOZ_ASSERT(aBuffer || !aLength, "Null buffer passed to SetTextInternal!"); // sanitize arguments uint32_t textLength = mText.GetLength(); if (aOffset > textLength) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } if (aCount > textLength - aOffset) { aCount = textLength - aOffset; } uint32_t endOffset = aOffset + aCount; // Make sure the text fragment can hold the new data. if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) { return NS_ERROR_OUT_OF_MEMORY; } nsIDocument *document = GetComposedDoc(); mozAutoDocUpdate updateBatch(document, aNotify); bool haveMutationListeners = aNotify && nsContentUtils::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED, this); RefPtr<nsAtom> oldValue; if (haveMutationListeners) { oldValue = GetCurrentValueAtom(); } if (aNotify) { CharacterDataChangeInfo info = { aOffset == textLength, aOffset, endOffset, aLength, aDetails }; nsNodeUtils::CharacterDataWillChange(this, info); } Directionality oldDir = eDir_NotSet; bool dirAffectsAncestor = (NodeType() == TEXT_NODE && TextNodeWillChangeDirection(this, &oldDir, aOffset)); if (aOffset == 0 && endOffset == textLength) { // Replacing whole text or old text was empty. Don't bother to check for // bidi in this string if the document already has bidi enabled. // If this is marked as "maybe modified frequently", the text should be // stored as char16_t since converting char* to char16_t* is expensive. bool ok = mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled(), HasFlag(NS_MAYBE_MODIFIED_FREQUENTLY)); NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); } else if (aOffset == textLength) { // Appending to existing bool ok = mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled(), HasFlag(NS_MAYBE_MODIFIED_FREQUENTLY)); NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); } else { // Merging old and new bool bidi = mText.IsBidi(); // Allocate new buffer int32_t newLength = textLength - aCount + aLength; // Use nsString and not nsAutoString so that we get a nsStringBuffer which // can be just AddRefed in nsTextFragment. nsString to; to.SetCapacity(newLength); // Copy over appropriate data if (aOffset) { mText.AppendTo(to, 0, aOffset); } if (aLength) { to.Append(aBuffer, aLength); if (!bidi && (!document || !document->GetBidiEnabled())) { bidi = HasRTLChars(MakeSpan(aBuffer, aLength)); } } if (endOffset != textLength) { mText.AppendTo(to, endOffset, textLength - endOffset); } // If this is marked as "maybe modified frequently", the text should be // stored as char16_t since converting char* to char16_t* is expensive. // Use char16_t also when we have bidi characters. bool use2b = HasFlag(NS_MAYBE_MODIFIED_FREQUENTLY) || bidi; bool ok = mText.SetTo(to, false, use2b); mText.SetBidi(bidi); NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); } UnsetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE); if (document && mText.IsBidi()) { // If we found bidi characters in mText.SetTo() above, indicate that the // document contains bidi characters. document->SetBidiEnabled(); } if (dirAffectsAncestor) { // dirAffectsAncestor being true implies that we have a text node, see // above. MOZ_ASSERT(NodeType() == TEXT_NODE); TextNodeChangedDirection(static_cast<nsTextNode*>(this), oldDir, aNotify); } // Notify observers if (aNotify) { CharacterDataChangeInfo info = { aOffset == textLength, aOffset, endOffset, aLength, aDetails }; nsNodeUtils::CharacterDataChanged(this, info); if (haveMutationListeners) { InternalMutationEvent mutation(true, eLegacyCharacterDataModified); mutation.mPrevAttrValue = oldValue; if (aLength > 0) { nsAutoString val; mText.AppendTo(val); mutation.mNewAttrValue = NS_Atomize(val); } mozAutoSubtreeModified subtree(OwnerDoc(), this); (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe(); } } return NS_OK; }
VOID FatForceCacheMiss ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FAT_FLUSH_TYPE FlushType ) /*++ Routine Description: The following routine asks either Cc or Mm to get rid of any cached pages on a file. Note that this will fail if a user has mapped a file. If there is a shared cache map, purge the cache section. Otherwise we have to go and ask Mm to blow away the section. NOTE: This caller MUST own the Vcb exclusive. Arguments: Fcb - Supplies a pointer to an fcb FlushType - Specifies the kind of flushing to perform Return Value: None. --*/ { PVCB Vcb; BOOLEAN ChildrenAcquired = FALSE; PAGED_CODE(); // // If we can't wait, bail. // ASSERT( FatVcbAcquiredExclusive( IrpContext, Fcb->Vcb ) || FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) ); if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } // // If we are purging a directory file object, we must acquire all the // FCBs exclusive so that the parent directory is not being pinned. // Careful, we can collide with something acquiring up the tree like // an unpin repinned flush (FsRtlAcquireFileForCcFlush ...) of a parent // dir on extending writethrough of a child file (oops). So get things // going up the tree, not down. // if ((NodeType(Fcb) != FAT_NTC_FCB) && !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) { PLIST_ENTRY Links; PFCB TempFcb; ChildrenAcquired = TRUE; for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &Fcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) { TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks ); (VOID)FatAcquireExclusiveFcb( IrpContext, TempFcb ); } } (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); // // We use this flag to indicate to a close beneath us that // the Fcb resource should be freed before deleting the Fcb. // Vcb = Fcb->Vcb; SetFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); try { BOOLEAN DataSectionExists; BOOLEAN ImageSectionExists; PSECTION_OBJECT_POINTERS Section; if ( FlushType ) { (VOID)FatFlushFile( IrpContext, Fcb, FlushType ); } // // The Flush may have made the Fcb go away // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB)) { Section = &Fcb->NonPaged->SectionObjectPointers; DataSectionExists = (BOOLEAN)(Section->DataSectionObject != NULL); ImageSectionExists = (BOOLEAN)(Section->ImageSectionObject != NULL); // // Note, it is critical to do the Image section first as the // purge of the data section may cause the image section to go // away, but the opposite is not true. // if (ImageSectionExists) { (VOID)MmFlushImageSection( Section, MmFlushForWrite ); } if (DataSectionExists) { CcPurgeCacheSection( Section, NULL, 0, FALSE ); } } } finally { // // If we purging a directory file object, release all the Fcb // resources that we acquired above. The Dcb cannot have vanished // if there were Fcbs underneath it, and the Fcbs couldn't have gone // away since I own the Vcb. // if (ChildrenAcquired) { PLIST_ENTRY Links; PFCB TempFcb; for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &Fcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) { TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks ); FatReleaseFcb( IrpContext, TempFcb ); } } // // Since we have the Vcb exclusive we know that if any closes // come in it is because the CcPurgeCacheSection caused the // Fcb to go away. Also in close, the Fcb was released // before being freed. // if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) { ClearFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS ); FatReleaseFcb( (IRPCONTEXT), Fcb ); } } }
VOID FatSetFileObject ( IN PFILE_OBJECT FileObject OPTIONAL, IN TYPE_OF_OPEN TypeOfOpen, IN PVOID VcbOrFcbOrDcb, IN PCCB Ccb OPTIONAL ) /*++ Routine Description: This routine sets the file system pointers within the file object Arguments: FileObject - Supplies a pointer to the file object being modified, and can optionally be null. TypeOfOpen - Supplies the type of open denoted by the file object. This is only used by this procedure for sanity checking. VcbOrFcbOrDcb - Supplies a pointer to either a vcb, fcb, or dcb Ccb - Optionally supplies a pointer to a ccb Return Value: None. --*/ { PAGED_CODE(); DebugTrace(+1, Dbg, "FatSetFileObject, FileObject = %08lx\n", FileObject ); ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB)); ASSERT(((TypeOfOpen == UnopenedFileObject)) || ((TypeOfOpen == UserFileOpen) && (NodeType(VcbOrFcbOrDcb) == FAT_NTC_FCB) && (Ccb != NULL)) || ((TypeOfOpen == EaFile) && (NodeType(VcbOrFcbOrDcb) == FAT_NTC_FCB) && (Ccb == NULL)) || ((TypeOfOpen == UserDirectoryOpen) && ((NodeType(VcbOrFcbOrDcb) == FAT_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == FAT_NTC_ROOT_DCB)) && (Ccb != NULL)) || ((TypeOfOpen == UserVolumeOpen) && (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) && (Ccb != NULL)) || ((TypeOfOpen == VirtualVolumeFile) && (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) && (Ccb == NULL)) || ((TypeOfOpen == DirectoryFile) && ((NodeType(VcbOrFcbOrDcb) == FAT_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == FAT_NTC_ROOT_DCB)) && (Ccb == NULL))); // // If we were given an Fcb, Dcb, or Vcb, we have some processing to do. // ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB)); if ( VcbOrFcbOrDcb != NULL ) { // // Set the Vpb field in the file object, and if we were given an // Fcb or Dcb move the field over to point to the nonpaged Fcb/Dcb // if (NodeType(VcbOrFcbOrDcb) == FAT_NTC_VCB) { FileObject->Vpb = ((PVCB)VcbOrFcbOrDcb)->Vpb; } else { FileObject->Vpb = ((PFCB)VcbOrFcbOrDcb)->Vcb->Vpb; // // If this is a temporary file, note it in the FcbState // if (FlagOn(((PFCB)VcbOrFcbOrDcb)->FcbState, FCB_STATE_TEMPORARY)) { SetFlag(FileObject->Flags, FO_TEMPORARY_FILE); } } } ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB)); // // Now set the fscontext fields of the file object // if (ARGUMENT_PRESENT( FileObject )) { FileObject->FsContext = VcbOrFcbOrDcb; FileObject->FsContext2 = Ccb; } ASSERT((Ccb == NULL) || (NodeType(Ccb) == FAT_NTC_CCB)); // // And return to our caller // DebugTrace(-1, Dbg, "FatSetFileObject -> VOID\n", 0); return; }
TYPE_OF_OPEN FatDecodeFileObject ( IN PFILE_OBJECT FileObject, OUT PVCB *Vcb, OUT PFCB *FcbOrDcb, OUT PCCB *Ccb ) /*++ Routine Description: This procedure takes a pointer to a file object, that has already been opened by the Fat file system and figures out what really is opened. Arguments: FileObject - Supplies the file object pointer being interrogated Vcb - Receives a pointer to the Vcb for the file object. FcbOrDcb - Receives a pointer to the Fcb/Dcb for the file object, if one exists. Ccb - Receives a pointer to the Ccb for the file object, if one exists. Return Value: TYPE_OF_OPEN - returns the type of file denoted by the input file object. UserFileOpen - The FO represents a user's opened data file. Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb. UserDirectoryOpen - The FO represents a user's opened directory. Ccb, FcbOrDcb, and Vcb are set. FcbOrDcb points to a Dcb/RootDcb UserVolumeOpen - The FO represents a user's opened volume. Ccb and Vcb are set. FcbOrDcb is null. VirtualVolumeFile - The FO represents the special virtual volume file. Vcb is set, and Ccb and FcbOrDcb are null. DirectoryFile - The FO represents a special directory file. Vcb and FcbOrDcb are set. Ccb is null. FcbOrDcb points to a Dcb/RootDcb. EaFile - The FO represents an Ea Io stream file. FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb, and Ccb is null. --*/ { TYPE_OF_OPEN TypeOfOpen; PVOID FsContext; PVOID FsContext2; PAGED_CODE(); DebugTrace(+1, Dbg, "FatDecodeFileObject, FileObject = %08lx\n", FileObject); // // Reference the fs context fields of the file object, and zero out // the out pointer parameters. // FsContext = FileObject->FsContext; FsContext2 = FileObject->FsContext2; // // Special case the situation where FsContext is null // if (FsContext == NULL) { *Ccb = NULL; *FcbOrDcb = NULL; *Vcb = NULL; TypeOfOpen = UnopenedFileObject; } else { // // Now we can case on the node type code of the fscontext pointer // and set the appropriate out pointers // switch (NodeType(FsContext)) { case FAT_NTC_VCB: *Ccb = FsContext2; *FcbOrDcb = NULL; *Vcb = FsContext; TypeOfOpen = ( *Ccb == NULL ? VirtualVolumeFile : UserVolumeOpen ); break; case FAT_NTC_ROOT_DCB: case FAT_NTC_DCB: *Ccb = FsContext2; *FcbOrDcb = FsContext; *Vcb = (*FcbOrDcb)->Vcb; TypeOfOpen = ( *Ccb == NULL ? DirectoryFile : UserDirectoryOpen ); DebugTrace(0, Dbg, "Referencing directory: %Z\n", &(*FcbOrDcb)->FullFileName); break; case FAT_NTC_FCB: *Ccb = FsContext2; *FcbOrDcb = FsContext; *Vcb = (*FcbOrDcb)->Vcb; TypeOfOpen = ( *Ccb == NULL ? EaFile : UserFileOpen ); DebugTrace(0, Dbg, "Referencing file: %Z\n", &(*FcbOrDcb)->FullFileName); break; default: FatBugCheck( NodeType(FsContext), 0, 0 ); } } // // and return to our caller // DebugTrace(-1, Dbg, "FatDecodeFileObject -> %08lx\n", TypeOfOpen); return TypeOfOpen; }
__drv_mustHoldCriticalRegion NTSTATUS FatCommonClose ( IN PVCB Vcb, IN PFCB Fcb, IN PCCB Ccb, IN TYPE_OF_OPEN TypeOfOpen, IN BOOLEAN Wait, OUT PBOOLEAN VcbDeleted OPTIONAL ) /*++ Routine Description: This is the common routine for closing a file/directory called by both the fsd and fsp threads. Close is invoked whenever the last reference to a file object is deleted. Cleanup is invoked when the last handle to a file object is closed, and is called before close. The function of close is to completely tear down and remove the fcb/dcb/ccb structures associated with the file object. Arguments: Fcb - Supplies the file to process. Wait - If this is TRUE we are allowed to block for the Vcb, if FALSE then we must try to acquire the Vcb anyway. VcbDeleted - Returns whether the VCB was deleted by this call. Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_SUCCESS; PDCB ParentDcb; BOOLEAN RecursiveClose; BOOLEAN LocalVcbDeleted; IRP_CONTEXT IrpContext; PAGED_CODE(); DebugTrace(+1, Dbg, "FatCommonClose...\n", 0); // // Initailize the callers variable, if needed. // LocalVcbDeleted = FALSE; if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } // // Special case the unopened file object // if (TypeOfOpen == UnopenedFileObject) { DebugTrace(0, Dbg, "Close unopened file object\n", 0); Status = STATUS_SUCCESS; DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); return Status; } // // Set up our stack IrpContext. // RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT; IrpContext.NodeByteSize = sizeof( IrpContext ); IrpContext.MajorFunction = IRP_MJ_CLOSE; IrpContext.Vcb = Vcb; if (Wait) { SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); } // // Acquire exclusive access to the Vcb and enqueue the irp if we didn't // get access. // #pragma prefast( suppress: 28137, "prefast wants Wait to be a constant, but that's not possible for fastfat" ) if (!ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait )) { return STATUS_PENDING; } // // The following test makes sure that we don't blow away an Fcb if we // are trying to do a Supersede/Overwrite open above us. This test // does not apply for the EA file. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) && Vcb->EaFcb != Fcb) { ExReleaseResourceLite( &Vcb->Resource ); return STATUS_PENDING; } // // Setting the following flag prevents recursive closes of directory file // objects, which are handled in a special case loop. // if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS) ) { RecursiveClose = TRUE; } else { SetFlag(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS); RecursiveClose = FALSE; // // Since we are at the top of the close chain, we need to add // a reference to the VCB. This will keep it from going away // on us until we are ready to check for a dismount below. // Vcb->OpenFileCount += 1; } try { // // Case on the type of open that we are trying to close. // switch (TypeOfOpen) { case VirtualVolumeFile: DebugTrace(0, Dbg, "Close VirtualVolumeFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) ); InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case UserVolumeOpen: DebugTrace(0, Dbg, "Close UserVolumeOpen\n", 0); Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); try_return( Status = STATUS_SUCCESS ); break; case EaFile: DebugTrace(0, Dbg, "Close EaFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) ); InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case DirectoryFile: DebugTrace(0, Dbg, "Close DirectoryFile\n", 0); InterlockedDecrement( (LONG*)&Fcb->Specific.Dcb.DirectoryFileOpenCount ); // // Remove this internal open from the count. // InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) ); // // If this is the root directory, it is a residual open // as well. // if (NodeType( Fcb ) == FAT_NTC_ROOT_DCB) { InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) ); } // // If this is a recursive close, just return here. // if ( RecursiveClose ) { try_return( Status = STATUS_SUCCESS ); } else { break; } case UserDirectoryOpen: case UserFileOpen: DebugTrace(0, Dbg, "Close UserFileOpen/UserDirectoryOpen\n", 0); // // Uninitialize the cache map if we no longer need to use it // if ((NodeType(Fcb) == FAT_NTC_DCB) && IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) && (Fcb->OpenCount == 1) && (Fcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject = Fcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize the stream file object\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); // // Dereference the directory file. This may cause a close // Irp to be processed, so we need to do this before we destory // the Fcb. // Fcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); } Fcb->OpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); break; default: #pragma prefast( suppress: 28159, "if the type of open is unknown, we seriously messed up." ) FatBugCheck( TypeOfOpen, 0, 0 ); } // // At this point we've cleaned up any on-disk structure that needs // to be done, and we can now update the in-memory structures. // Now if this is an unreferenced FCB or if it is // an unreferenced DCB (not the root) then we can remove // the fcb and set our ParentDcb to non null. // if (((NodeType(Fcb) == FAT_NTC_FCB) && (Fcb->OpenCount == 0)) || ((NodeType(Fcb) == FAT_NTC_DCB) && (IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) && (Fcb->OpenCount == 0) && (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0))) { ParentDcb = Fcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &Fcb ); // // Uninitialize our parent's cache map if we no longer need // to use it. // while ((NodeType(ParentDcb) == FAT_NTC_DCB) && IsListEmpty(&ParentDcb->Specific.Dcb.ParentDcbQueue) && (ParentDcb->OpenCount == 0) && (ParentDcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject; DirectoryFileObject = ParentDcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); ParentDcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); // // Now, if the ObDereferenceObject() caused the final close // to come in, then blow away the Fcb and continue up, // otherwise wait for Mm to to dereference its file objects // and stop here.. // if ( ParentDcb->Specific.Dcb.DirectoryFileOpenCount == 0) { PDCB CurrentDcb; CurrentDcb = ParentDcb; ParentDcb = CurrentDcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &CurrentDcb ); } else { break; } } } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { DebugUnwind( FatCommonClose ); // // We are done processing the close. If we are the top of the close // chain, see if the VCB can go away. We have biased the open count by // one, so we need to take that into account. // if (!RecursiveClose) { // // See if there is only one open left. If so, it is ours. We only want // to check for a dismount if a dismount is not already in progress. // We also only do this if the caller can handle the VCB going away. // This is determined by whether they passed in the VcbDeleted argument. // if (Vcb->OpenFileCount == 1 && !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) && ARGUMENT_PRESENT( VcbDeleted )) { // // We need the global lock, which must be acquired before the // VCB. Since we already have the VCB, we have to drop and // reaquire here. Note that we always want to wait from this // point on. Note that the VCB cannot go away, since we have // biased the open file count. // FatReleaseVcb( &IrpContext, Vcb ); SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); #pragma prefast( suppress: 28137, "prefast wants the wait parameter in this macro expansion to be a constant, unfortunately this is not possible" ) FatAcquireExclusiveGlobal( &IrpContext ); FatAcquireExclusiveVcb( &IrpContext, Vcb ); // // We have our locks in the correct order. Remove our // extra open and check for a dismount. Note that if // something changed while we dropped the lock, it will // not matter, since the dismount code does the correct // checks to make sure the volume can really go away. // Vcb->OpenFileCount -= 1; LocalVcbDeleted = FatCheckForDismount( &IrpContext, Vcb, FALSE ); FatReleaseGlobal( &IrpContext ); // // Let the caller know what happened, if they want this information. // if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } } else { // // The volume cannot go away now. Just remove our extra reference. // Vcb->OpenFileCount -= 1; } // // If the VCB is still around, clear our recursion flag. // if (!LocalVcbDeleted) { ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS ); } } // // Only release the VCB if it did not go away. // if (!LocalVcbDeleted) { FatReleaseVcb( &IrpContext, Vcb ); } DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); } return Status; }
NTSTATUS NdasFatCommonFlushBuffers ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for flushing a buffer. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; BOOLEAN VcbAcquired = FALSE; BOOLEAN FcbAcquired = FALSE; PDIRENT Dirent; PBCB DirentBcb = NULL; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; PAGED_CODE(); IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject); // // Extract and decode the file object // FileObject = IrpSp->FileObject; TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); // // CcFlushCache is always synchronous, so if we can't wait enqueue // the irp to the Fsp. // if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) { Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status ); return Status; } Status = STATUS_SUCCESS; try { if (!FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { do { 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 ); } secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); if (secondaryRequest == NULL) { NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES ); Status = STATUS_INSUFFICIENT_RESOURCES; break; } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, IrpContext->OriginatingIrp, IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), Ccb->PrimaryFileHandle ); ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); break; } KeClearEvent (&secondaryRequest->CompleteEvent); if (BooleanFlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { 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 ); } if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) { ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; ASSERT(NTOHL(ndfsWinxpReplytHeader->Status4) == STATUS_SUCCESS); } if (secondaryRequest) { DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } if ( secondarySessionResourceAcquired == TRUE ) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); secondarySessionResourceAcquired = FALSE; } break; } while(0); } Status = STATUS_SUCCESS; // // Case on the type of open that we are trying to flush // switch (TypeOfOpen) { case VirtualVolumeFile: case EaFile: case DirectoryFile: DebugTrace(0, Dbg, "Flush that does nothing\n", 0); break; case UserFileOpen: DebugTrace(0, Dbg, "Flush User File Open\n", 0); (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); FcbAcquired = TRUE; FatVerifyFcb( IrpContext, Fcb ); // // If the file is cached then flush its cache // Status = FatFlushFile( IrpContext, Fcb, Flush ); // // Also update and flush the file's dirent in the parent directory if the // file flush worked. // if (NT_SUCCESS( Status )) { // // Insure that we get the filesize to disk correctly. This is // benign if it was already good. // // (why do we need to do this?) // SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); #if 0 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); #endif // // Flush the volume file to get any allocation information // updates to disk. // if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) { Status = FatFlushFat( IrpContext, Vcb ); ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT); } // // Set the write through bit so that these modifications // will be completed with the request. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); } break; case UserDirectoryOpen: // // If the user had opened the root directory then we'll // oblige by flushing the volume. // if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) { DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0); break; } case UserVolumeOpen: DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0); // // Acquire exclusive access to the Vcb. // { BOOLEAN Finished; Finished = FatAcquireExclusiveVcb( IrpContext, Vcb ); ASSERT( Finished ); } VcbAcquired = TRUE; // // Mark the volume clean and then flush the volume file, // and then all directories // Status = FatFlushVolume( IrpContext, Vcb, Flush ); // // If the volume was dirty, do the processing that the delayed // callback would have done. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) { // // Cancel any pending clean volumes. // (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc ); // // The volume is now clean, note it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { FatMarkVolume( IrpContext, Vcb, VolumeClean ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); } // // Unlock the volume if it is removable. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); } } break; default: FatBugCheck( TypeOfOpen, 0, 0 ); } FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinRepinnedBcbs( IrpContext ); } finally { DebugUnwind( FatCommonFlushBuffers ); if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); if (secondarySessionResourceAcquired) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); } FatUnpinBcb( IrpContext, DirentBcb ); if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); } if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); } // // If this is a normal termination then pass the request on // to the target device object. // if (!AbnormalTermination()) { NTSTATUS DriverStatus; PIO_STACK_LOCATION NextIrpSp; // // Get the next stack location, and copy over the stack location // NextIrpSp = IoGetNextIrpStackLocation( Irp ); *NextIrpSp = *IrpSp; // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatFlushCompletionRoutine, ULongToPtr( Status ), TRUE, TRUE, TRUE ); // // Send the request. // DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp); Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ? Status : DriverStatus; // // Free the IrpContext and return to the caller. // FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS ); } DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status); } return Status; }