/* * Generic function to deal with the creating/lookup of inodes. * */ static TInode* doInodeGetInode(TSuperBlock *Super, TInode *ParentInode, ULONG InodeNo, char *FileName, int NameLen) { TInode *inode; ext2_inode *ext2inode; inode = 0; // assume error VxdDebugPrint(D_INODE, "doInodeGetInode: dev=%s, inono=%lu", Super->DeviceName, InodeNo); /* * Sometimes directories contain entries with InodeNo=0 * Don't consider this an error, just return silently */ if (!InodeNo) return 0; /* * First, see if it's in the the Table, if not * create a TInode and get it from disk (actually the block * my be in the cache) */ if (!(inode = InodeGetFromTable(Super, InodeNo))) { /* * Not present, so first create a TInode object */ if (!(inode = InodeCreate(Super, ParentInode, InodeNo))) { VxdDebugPrint(D_ERROR, "doInodeGetInode: could not create a TInode"); goto doget_inode_done; } /* * Get it from the file system */ if (!Ext2ReadInode(inode)) { VxdDebugPrint(D_ERROR, "doInodeGetInode: could not readinode from disk"); InodeDestroy(inode); inode = (TInode *) 0; goto doget_inode_done; } ext2inode = InodeLock(inode); inode->DosAttrib = UnixToWinAttrib(ext2inode, FileName, NameLen); inode->Mode = ext2inode->i_mode; InodeUnlock(inode); } inode->nrClients++; // increase reference count for this inode doget_inode_done: VxdDebugPrint(D_INODE, "doInodeGetInode: done (attrib=%i)", inode ? inode->DosAttrib : -1); return inode; }
NTSTATUS Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; 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; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; PUCHAR Buffer; __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; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.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, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) || IsFileDeleted(Fcb->Mcb)) { 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; DbgBreak(); __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; DbgBreak(); __leave; } if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) { CcFlushCache( FileObject->SectionObjectPointer, &ByteOffset, Length, &Irp->IoStatus ); if (!NT_SUCCESS(Irp->IoStatus.Status)) { __leave; } } ReturnedLength = Length; if (PagingIo) { if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } else { if (Nocache) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } if (!FsRtlCheckLockForReadAccess( &Fcb->FileLockAnchor, Irp )) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.FileSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.FileSize.QuadPart) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } if (!IsDirectory(Fcb) && 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); } if (!Nocache) { if (IsDirectory(Fcb)) { __leave; } 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)) { CcMdlRead( FileObject, (&ByteOffset), ReturnedLength, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { Status = STATUS_INVALID_USER_BUFFER; DbgBreak(); __leave; } if (!CcCopyRead(FileObject, &ByteOffset, ReturnedLength, Ext2CanIWait(), Buffer, &Irp->IoStatus)) { if (Ext2CanIWait() || !CcCopyRead(FileObject, &ByteOffset, ReturnedLength, TRUE, Buffer, &Irp->IoStatus)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } Status = Irp->IoStatus.Status; } } else { ULONG BytesRead = ReturnedLength; PUCHAR SystemVA = Ext2GetUserBuffer(IrpContext->Irp); if (ByteOffset.QuadPart + BytesRead > Fcb->Header.ValidDataLength.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.ValidDataLength.QuadPart) { if (SystemVA) { SafeZeroMemory(SystemVA, Length); } Irp->IoStatus.Information = ReturnedLength; Status = STATUS_SUCCESS; __leave; } else { BytesRead = (ULONG)(Fcb->Header.ValidDataLength.QuadPart - ByteOffset.QuadPart); if (SystemVA) { SafeZeroMemory(SystemVA + BytesRead, Length - BytesRead); } } } Status = Ext2LockUserBuffer( IrpContext->Irp, BytesRead, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Status = Ext2ReadInode( IrpContext, Vcb, Fcb->Mcb, ByteOffset.QuadPart, NULL, BytesRead, TRUE, NULL ); /* we need re-queue this request in case STATUS_CANT_WAIT and fail it in other failure cases */ if (!NT_SUCCESS(Status)) { __leave; } /* pended by low level device */ if (Status == STATUS_PENDING) { IrpContext->Irp = Irp = NULL; __leave; } Irp = IrpContext->Irp; ASSERT(Irp); Status = Irp->IoStatus.Status; if (!NT_SUCCESS(Status)) { Ext2NormalizeAndRaiseStatus(IrpContext, Status); } } Irp->IoStatus.Information = ReturnedLength; } __finally { 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) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { if (NT_SUCCESS(Status)) { if (!PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } FileObject->Flags |= FO_FILE_FAST_IO_READ; } } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2ReadFile: %wZ fetch at Off=%I64xh Len=%xh Paging=%xh Nocache=%xh Returned=%xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache, ReturnedLength, Status)); return Status; }
/************************************************************************* * * Function: Ext2CommonClose() * * Description: * The actual work is performed here. This routine may be invoked in one' * of the two possible contexts: * (a) in the context of a system worker thread * (b) in the context of the original caller * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: Does not matter! * *************************************************************************/ NTSTATUS NTAPI Ext2CommonClose( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, BOOLEAN FirstAttempt ) { NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION PtrIoStackLocation = NULL; PFILE_OBJECT PtrFileObject = NULL; PtrExt2FCB PtrFCB = NULL; PtrExt2CCB PtrCCB = NULL; PtrExt2VCB PtrVCB = NULL; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; PERESOURCE PtrResourceAcquired = NULL; PERESOURCE PtrPagingIoResourceAcquired = NULL; BOOLEAN CompleteIrp = TRUE; BOOLEAN PostRequest = FALSE; BOOLEAN AcquiredVCB = FALSE; BOOLEAN BlockForResource; int i = 1; try { // First, get a pointer to the current I/O stack location PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ASSERT(PtrIoStackLocation); PtrFileObject = PtrIoStackLocation->FileObject; ASSERT(PtrFileObject); if( !PtrFileObject->FsContext2 ) { // This must be a Cleanup request received // as a result of IoCreateStreamFileObject // Only such a File object would have a NULL CCB DebugTrace( DEBUG_TRACE_SPECIAL, " === Close with NULL CCB", 0); if( PtrFileObject ) { DebugTrace( DEBUG_TRACE_SPECIAL, "###### File Pointer 0x%LX [Close]", PtrFileObject); } try_return(); } // Get the FCB and CCB pointers Ext2GetFCB_CCB_VCB_FromFileObject ( PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ASSERT( PtrVCB ); if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) { DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); } else { DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -null-", 0); } // (a) Acquiring the VCBResource Exclusively... // This is done to synchronise with the close and cleanup routines... // if( ExTryToAcquireResourceExclusiveLite(&(PtrVCB->VCBResource) ) ) BlockForResource = !FirstAttempt; if( !FirstAttempt ) { DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Close]", 0); } else { DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [Close]", 0); } if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } i = 1; while( !AcquiredVCB ) { DebugTraceState( "VCB AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); if(! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) { DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Close]", 0); if( BlockForResource && i != 1000 ) { LARGE_INTEGER Delay; //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); Delay.QuadPart = -500 * i; KeDelayExecutionThread( KernelMode, FALSE, &Delay ); DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); } else { if( i == 1000 ) DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); PostRequest = TRUE; try_return( RC = STATUS_PENDING ); } } else { DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in [Close]", 0); AcquiredVCB = TRUE; } i *= 10; } // (b) Acquire the file (FCB) exclusively if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) { // This FCB is an FCB indeed. ;) // So acquiring it exclusively... // This is done to synchronise with read/write routines... if( !FirstAttempt ) { DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively [Close]", 0); } else { DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [Close]", 0); } if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } PtrReqdFCB = &PtrFCB->NTRequiredFCB; i = 1; while( !PtrResourceAcquired ) { DebugTraceState( "FCBMain AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); if(! ExAcquireResourceExclusiveLite( &(PtrReqdFCB->MainResource), FALSE ) ) { DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); if( BlockForResource && i != 1000 ) { LARGE_INTEGER Delay; //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); Delay.QuadPart = -500 * i; KeDelayExecutionThread( KernelMode, FALSE, &Delay ); DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); } else { if( i == 1000 ) DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); PostRequest = TRUE; try_return( RC = STATUS_PENDING ); } } else { DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); PtrResourceAcquired = & ( PtrReqdFCB->MainResource ); } i *= 10; } i = 1; while( !PtrPagingIoResourceAcquired ) { DebugTraceState( "FCBPaging AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); if(! ExAcquireResourceExclusiveLite( &(PtrReqdFCB->PagingIoResource), FALSE ) ) { DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); if( BlockForResource && i != 1000 ) { LARGE_INTEGER Delay; // KeSetPriorityThread( PsGetCurrentThread(), LOW_REALTIME_PRIORITY ); Delay.QuadPart = -500 * i; KeDelayExecutionThread( KernelMode, FALSE, &Delay ); DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); } else { if( i == 1000 ) DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); PostRequest = TRUE; try_return( RC = STATUS_PENDING ); } } else { DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); PtrPagingIoResourceAcquired = & ( PtrReqdFCB->PagingIoResource ); } i *= 10; } // (c) Delete the CCB structure (free memory) RemoveEntryList( &PtrCCB->NextCCB ); Ext2ReleaseCCB( PtrCCB ); PtrFileObject->FsContext2 = NULL; // (d) Decrementing the Reference Count... if( PtrFCB->ReferenceCount ) { InterlockedDecrement( &PtrFCB->ReferenceCount ); } else { Ext2BreakPoint(); } DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Close]", PtrFCB->ReferenceCount ); DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Close]", PtrFCB->OpenHandleCount ); if( PtrFCB->ReferenceCount == 0 ) { // Attempting to update time stamp values // Errors are ignored... // Not considered as critical errors... { ULONG CreationTime, AccessTime, ModificationTime; EXT2_INODE Inode; CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) { // Update time stamps in the inode... Inode.i_ctime = CreationTime; Inode.i_atime = AccessTime; Inode.i_mtime = ModificationTime; // Updating the inode... Ext2WriteInode( NULL, PtrVCB, PtrFCB->INodeNo, &Inode ); } } if( PtrFCB->INodeNo == EXT2_ROOT_INO ) { // // Root Directory FCB // Preserve this // FSD has a File Object for this FCB... // DebugTrace(DEBUG_TRACE_MISC, "^^^^^Root Directory FCB ; leaveing it alone[Close]", 0); // Do nothing... } else if( PtrFCB->DcbFcb.Dcb.PtrDirFileObject ) { // // If this is a FCB created on the FSD's initiative // Leave it alone // DebugTrace(DEBUG_TRACE_MISC, "^^^^^FCB Created on the FSD's initiative; leaveing it alone[Close]", 0); if( !PtrFCB->ClosableFCBs.OnClosableFCBList ) { InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, &PtrFCB->ClosableFCBs.ClosableFCBList ); PtrVCB->ClosableFCBs.Count++; PtrFCB->ClosableFCBs.OnClosableFCBList = TRUE; } if( PtrVCB->ClosableFCBs.Count > EXT2_MAXCLOSABLE_FCBS_UL ) { PtrExt2FCB PtrTempFCB = NULL; // Checking if Closable FCBs are too many in number... // Shouldn't block the // Should do this asynchronously... // Maybe later... PLIST_ENTRY PtrEntry = NULL; PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); PtrTempFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); if( Ext2CloseClosableFCB( PtrTempFCB ) ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Close]", PtrTempFCB ); ExFreePool( PtrTempFCB ); PtrVCB->ClosableFCBs.Count--; } else { // Put the FCB back in the list... InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, &PtrTempFCB->ClosableFCBs.ClosableFCBList ); } DebugTrace( DEBUG_TRACE_SPECIAL, "ClosableFCBs Count = %ld [Close]", PtrVCB->ClosableFCBs.Count ); } } else { // Remove this FCB as well... DebugTrace(DEBUG_TRACE_MISC, "^^^^^Deleting FCB [Close]", 0); RemoveEntryList( &PtrFCB->NextFCB ); if ( PtrPagingIoResourceAcquired ) { Ext2ReleaseResource(PtrPagingIoResourceAcquired); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrPagingIoResourceAcquired->ActiveCount, PtrPagingIoResourceAcquired->NumberOfExclusiveWaiters, PtrPagingIoResourceAcquired->NumberOfSharedWaiters ); PtrPagingIoResourceAcquired = NULL; } if ( PtrResourceAcquired ) { Ext2ReleaseResource(PtrResourceAcquired); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrResourceAcquired->ActiveCount, PtrResourceAcquired->NumberOfExclusiveWaiters, PtrResourceAcquired->NumberOfSharedWaiters ); if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } PtrResourceAcquired = NULL; } Ext2ReleaseFCB( PtrFCB ); } } CompleteIrp = TRUE; } else { // This must be a volume close... // What do I do now? ;) DebugTrace(DEBUG_TRACE_MISC, "VCB Close Requested !!!", 0); CompleteIrp = TRUE; } try_return(); try_exit: NOTHING; } finally { if ( PtrPagingIoResourceAcquired ) { Ext2ReleaseResource(PtrPagingIoResourceAcquired); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrPagingIoResourceAcquired->ActiveCount, PtrPagingIoResourceAcquired->NumberOfExclusiveWaiters, PtrPagingIoResourceAcquired->NumberOfSharedWaiters ); PtrPagingIoResourceAcquired = NULL; } if ( PtrResourceAcquired ) { Ext2ReleaseResource(PtrResourceAcquired); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrResourceAcquired->ActiveCount, PtrResourceAcquired->NumberOfExclusiveWaiters, PtrResourceAcquired->NumberOfSharedWaiters ); if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } PtrResourceAcquired = NULL; } if (AcquiredVCB) { ASSERT(PtrVCB); Ext2ReleaseResource(&(PtrVCB->VCBResource)); DebugTraceState( "VCB AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Close]", 0); AcquiredVCB = FALSE; if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } } if( PostRequest ) { RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if( CompleteIrp && RC != STATUS_PENDING ) { // complete the IRP IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); Ext2ReleaseIrpContext( PtrIrpContext ); } } // end of "finally" processing return(RC); }
/************************************************************************* * * Function: Ext2QueryDirectory() * * Description: * Query directory request. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: STATUS_SUCCESS/Error * *************************************************************************/ NTSTATUS NTAPI Ext2QueryDirectory( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, #ifdef _GNU_NTIFS_ PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, #else PIO_STACK_LOCATION PtrIoStackLocation, #endif PFILE_OBJECT PtrFileObject, PtrExt2FCB PtrFCB, PtrExt2CCB PtrCCB) { NTSTATUS RC = STATUS_SUCCESS; BOOLEAN PostRequest = FALSE; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; BOOLEAN CanWait = FALSE; PtrExt2VCB PtrVCB = NULL; BOOLEAN AcquiredFCB = FALSE; unsigned long BufferLength = 0; unsigned long BufferIndex = 0; unsigned long FileIndex = 0; PUNICODE_STRING PtrSearchPattern = NULL; FILE_INFORMATION_CLASS FileInformationClass; BOOLEAN RestartScan = FALSE; BOOLEAN ReturnSingleEntry = FALSE; BOOLEAN IndexSpecified = FALSE; unsigned char *Buffer = NULL; BOOLEAN FirstTimeQuery = FALSE; unsigned long StartingIndexForSearch = 0; unsigned long BytesReturned = 0; BOOLEAN BufferUsedup = FALSE; BOOLEAN SearchWithWildCards = FALSE; PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL; PEXT2_DIR_ENTRY PtrDirEntry = NULL; PEXT2_INODE PtrInode = NULL; unsigned long LogicalBlockSize; unsigned long ThisBlock; // The starting Physical Block No... //LARGE_INTEGER StartPhysicalBlock; LARGE_INTEGER StartBufferOffset ; ULONG PinBufferLength; // Buffer Control Block PBCB PtrBCB = NULL; BYTE * PtrPinnedBlockBuffer = NULL; unsigned int j; DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer ); try { // Validate the sent-in FCB if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { // We will only allow notify requests on directories. RC = STATUS_INVALID_PARAMETER; } PtrReqdFCB = &(PtrFCB->NTRequiredFCB); CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); PtrVCB = PtrFCB->PtrVCB; // // Asynchronous IO requested // Posting request... // /* * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL * requests aren't handled in the worker thread yet. I tried * adding handling of them to the worked routine, but there * were problems with accessing the PtrIoStackLocation-> * Parameters.QueryDirectory.FileName variable. * -- Filip Navara, 18/08/2004 */ #if 0 if (!CanWait) { PostRequest = TRUE; try_return(RC = STATUS_PENDING); } #endif // Obtain the callers parameters BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length; PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName; FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass; FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex; // Some additional arguments that affect the FSD behavior RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN); ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY); IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED); // // Acquiring exclusive access to the FCB. // This is not mandatory // DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); AcquiredFCB = TRUE; // We must determine the buffer pointer to be used. Since this // routine could either be invoked directly in the context of the // calling thread, or in the context of a worker thread, here is // a general way of determining what we should use. Buffer = Ext2GetCallersBuffer ( PtrIrp ); // The method of determining where to look from and what to look for is // unfortunately extremely confusing. However, here is a methodology you // you can broadly adopt: // (a) You have to maintain a search buffer per CCB structure. // (b) This search buffer is initialized the very first time // a query directory operation is performed using the file object. // (For the sample FSD, the search buffer is stored in the // DirectorySearchPattern field) // However, the caller still has the option of "overriding" this stored // search pattern by supplying a new one in a query directory operation. // if( PtrCCB->DirectorySearchPattern.Length ) { if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0); } DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); } if (PtrSearchPattern != NULL) { // User has supplied a search pattern // Now validate that the search pattern is legitimate if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This must be the very first query request. FirstTimeQuery = TRUE; } else { // We should ignore the search pattern in the CCB and instead, // use the user-supplied pattern for this particular query // directory request. Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); } // Now, allocate enough memory to contain the caller // supplied search pattern and fill in the DirectorySearchPattern // field in the CCB Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern ); /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) ); */ } else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This MUST be the first directory query operation (else the // DirectorySearchPattern field would never be empty. Also, the caller // has neglected to provide a pattern so we MUST invent one. // Use "*" (following NT conventions) as your search pattern // and store it in the PtrCCB->DirectorySearchPattern field. /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/ Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" ); FirstTimeQuery = TRUE; } else { // The caller has not supplied any search pattern... // Using previously supplied pattern PtrSearchPattern = &PtrCCB->DirectorySearchPattern; } if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 ); } DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern ); // There is one other piece of information that your FSD must store // in the CCB structure for query directory support. This is the index // value (i.e. the offset in your on-disk directory structure) from // which you should start searching. // However, the flags supplied with the IRP can make us override this // as well. if (FileIndex) { // Caller has told us wherefrom to begin. // You may need to round this to an appropriate directory entry // entry alignment value. StartingIndexForSearch = FileIndex; } else if (RestartScan) { StartingIndexForSearch = 0; } else { // Get the starting offset from the CCB. StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart; } // Read in the file inode if it hasn't already been read... Ext2InitializeFCBInodeInfo( PtrFCB ); if (PtrFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), TRUE, // We will utilize pin access for directories &(Ext2GlobalData.CacheMgrCallBacks), // callbacks PtrCCB); // The context used in callbacks } // // Read in the next Data Block of this directory // LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize ); StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary... PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart; if ( !CcMapData( PtrFileObject, &StartBufferOffset, PinBufferLength, TRUE, &PtrBCB, (PVOID*)&PtrPinnedBlockBuffer ) ) { // Read Failure DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0); try_return(); } else { DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); } PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) ); // // Walking through the directory entries... for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; ) { PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ]; StartingIndexForSearch += PtrDirEntry->rec_len; PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch; if( PtrDirEntry->inode == 0 ) { continue; } if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 ) { // // This should not happen // Hqw can this be so!!! // Ext2BreakPoint(); if( BothDirInformation ) { BothDirInformation->NextEntryOffset = 0; } if( !BytesReturned ) { if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; } break; } // Does this entry match the search criterian? // Checking // { UNICODE_STRING FileName; LONG Matched = 0; // Constructing a counted Unicode string out of PtrDirEntry Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len ); if ( SearchWithWildCards ) { Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL ); } else { Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE ); } Ext2DeallocateUnicodeString( &FileName ); if( !Matched ) { continue; } } switch( FileInformationClass ) { case FileBothDirectoryInformation: DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( BothDirInformation ) BothDirInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) ); BothDirInformation->EaSize = 0; BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size; BothDirInformation->ChangeTime.QuadPart = 0; BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } BothDirInformation->FileIndex = StartingIndexForSearch; BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; BothDirInformation->ShortNameLength = 0; BothDirInformation->ShortName[0] = 0; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j]; BothDirInformation->FileName[ j ] = PtrDirEntry->name[j]; // if( j < 11 ) // BothDirInformation->ShortName[j] = PtrDirEntry->name[j]; } /* if( j < 11 ) { BothDirInformation->ShortNameLength = j * 2 + 2; BothDirInformation->ShortName[ j ] = 0; } else { BothDirInformation->ShortNameLength = 24; BothDirInformation->ShortName[ 11 ] = 0; }*/ BothDirInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) BothDirInformation->NextEntryOffset = ThisBlock; else BothDirInformation->NextEntryOffset = 0; break; case FileDirectoryInformation: // DirectoryInformation DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( DirectoryInformation ) DirectoryInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) ); DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size; DirectoryInformation->ChangeTime.QuadPart = 0; DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } DirectoryInformation->FileIndex = StartingIndexForSearch; DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j]; } DirectoryInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) DirectoryInformation->NextEntryOffset = ThisBlock; else DirectoryInformation->NextEntryOffset = 0; break; case FileFullDirectoryInformation: // FullDirInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 ); try_return(); case FileNamesInformation: // NamesInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 ); try_return(); default: DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 ); try_return( RC = STATUS_INVALID_INFO_CLASS ); } if( ReturnSingleEntry ) { break; } }// end of for... if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) ) { Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); PtrCCB->CurrentByteOffset.QuadPart = 0; if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; try_return(); } else if( BytesReturned ) { BothDirInformation->NextEntryOffset = 0; } try_exit: NOTHING; } finally { if( PtrInode ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode ); ExFreePool( PtrInode ); } if( PtrBCB ) { CcUnpinData( PtrBCB ); PtrBCB = NULL; } if (PostRequest) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Map the users buffer and then post the request. RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength); ASSERT(NT_SUCCESS(RC)); RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Complete the request. PtrIrp->IoStatus.Status = RC; PtrIrp->IoStatus.Information = BytesReturned; // Free up the Irp Context Ext2ReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); } // Flush the saved BCBs... // Ext2FlushSavedBCBs ( PtrIrpContext ); } return(RC); }