/************************************************************************* * * 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: Ext2NotifyChangeDirectory() * * Description: * Handle the notify request. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: STATUS_SUCCESS/Error * *************************************************************************/ NTSTATUS NTAPI Ext2NotifyChangeDirectory( 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 CompleteRequest = FALSE; BOOLEAN PostRequest = FALSE; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; BOOLEAN CanWait = FALSE; ULONG CompletionFilter = 0; BOOLEAN WatchTree = FALSE; PtrExt2VCB PtrVCB = NULL; BOOLEAN AcquiredFCB = FALSE; 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; CompleteRequest = TRUE; } PtrReqdFCB = &(PtrFCB->NTRequiredFCB); CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); PtrVCB = PtrFCB->PtrVCB; // Acquire the FCB resource shared DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared[DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) { DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [DirCtrl]", 0); PostRequest = TRUE; try_return(RC = STATUS_PENDING); } AcquiredFCB = TRUE; DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); // Obtain some parameters sent by the caller CompletionFilter = PtrIoStackLocation->Parameters.NotifyDirectory.CompletionFilter; WatchTree = (PtrIoStackLocation->Flags & SL_WATCH_TREE ? TRUE : FALSE); // If you wish to capture the subject context, you can do so as // follows: // { // PSECURITY_SUBJECT_CONTEXT SubjectContext; // SubjectContext = Ext2AllocatePool(PagedPool, // sizeof(SECURITY_SUBJECT_CONTEXT) ); // SeCaptureSubjectContext(SubjectContext); // } FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC)&(PtrVCB->NotifyIRPMutex), &(PtrVCB->NextNotifyIRP), (void *)PtrCCB, (PSTRING)(PtrFCB->FCBName->ObjectName.Buffer), WatchTree, FALSE, CompletionFilter, PtrIrp, NULL, // Ext2TraverseAccessCheck(...) ? NULL); // SubjectContext ? RC = STATUS_PENDING; try_exit: NOTHING; } finally { if (PostRequest) { // Perform appropriate post related processing here 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 ); AcquiredFCB = FALSE; } RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if (CompleteRequest) { PtrIrp->IoStatus.Status = RC; PtrIrp->IoStatus.Information = 0; // Free up the Irp Context Ext2ReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); } else { // Simply free up the IrpContext since the IRP has been queued Ext2ReleaseIrpContext(PtrIrpContext); } // Release the FCB resources if acquired. if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FReleased in [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); AcquiredFCB = FALSE; } } return(RC); }
/************************************************************************* * * Function: Ext2CommonFlush() * * 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: STATUS_SUCCESS/Error * *************************************************************************/ NTSTATUS NTAPI Ext2CommonFlush( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp) { 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; BOOLEAN AcquiredFCB = FALSE; BOOLEAN PostRequest = FALSE; BOOLEAN CanWait = TRUE; try { // First, get a pointer to the current I/O stack location PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ASSERT(PtrIoStackLocation); PtrFileObject = PtrIoStackLocation->FileObject; ASSERT(PtrFileObject); // Get the FCB and CCB pointers PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); ASSERT(PtrCCB); PtrFCB = PtrCCB->PtrFCB; AssertFCB( PtrFCB ); /*ASSERT(PtrFCB); ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB );*/ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); // Get some of the parameters supplied to us CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous. if (!CanWait) { PostRequest = TRUE; try_return(); } // Check the type of object passed-in. That will determine the course of // action we take. if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || (PtrFCB->FCBFlags & EXT2_FCB_ROOT_DIRECTORY)) { if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) { PtrVCB = (PtrExt2VCB)(PtrFCB); } else { PtrVCB = PtrFCB->PtrVCB; } // The caller wishes to flush all files for the mounted // logical volume. The flush volume routine below should simply // walk through all of the open file streams, acquire the // FCB resource, and request the flush operation from the Cache // Manager. Basically, the sequence of operations listed below // for a single file should be executed on all open files. Ext2FlushLogicalVolume(PtrIrpContext, PtrIrp, PtrVCB); try_return(); } if (!(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { // This is a regular file. ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); AcquiredFCB = TRUE; // Request the Cache Manager to perform a flush operation. // Further, instruct the Cache Manager that we wish to flush the // entire file stream. Ext2FlushAFile(PtrReqdFCB, &(PtrIrp->IoStatus)); RC = PtrIrp->IoStatus.Status; // All done. You may want to also flush the directory entry for the // file stream at this time. // Some log-based FSD implementations may wish to flush their // log files at this time. Finally, you should update the time-stamp // values for the file stream appropriately. This would involve // obtaining the current time and modifying the appropriate directory // entry fields. } try_exit: if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Flush]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Flush]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); AcquiredFCB = FALSE; } if (!PostRequest) { PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; NTSTATUS RC1 = STATUS_SUCCESS; // Send the request down at this point. // To do this, you must set the next IRP stack location, and // maybe set a completion routine. // Be careful about marking the IRP pending if the lower level // driver returned pending and you do have a completion routine! PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); *PtrNextIoStackLocation = *PtrIoStackLocation; // Set the completion routine to "eat-up" any // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower // level driver. IoSetCompletionRoutine(PtrIrp, Ext2FlushCompletion, NULL, TRUE, TRUE, TRUE); /* * The exception handlers propably masked out the * fact that PtrVCB was never set. * -- Filip Navara, 18/08/2004 */ PtrVCB = PtrFCB->PtrVCB; RC1 = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1); } } finally { if (PostRequest) { // Nothing to lock now. RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else { // Release the IRP context at this time. Ext2ReleaseIrpContext(PtrIrpContext); } } 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); }