|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dir.c
Abstract:
This module implements the file directory routines for the mailslot file system by the dispatch driver.
Author:
Manny Weiser (mannyw) 1-Feb-1991
Revision History:
--*/
#include "mailslot.h"
//
// Local debug trace level
//
#define Dbg (DEBUG_TRACE_DIR)
NTSTATUS MsCommonDirectoryControl ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp );
NTSTATUS MsQueryDirectory ( IN PROOT_DCB RootDcb, IN PROOT_DCB_CCB Ccb, IN PIRP Irp );
NTSTATUS MsNotifyChangeDirectory ( IN PROOT_DCB RootDcb, IN PROOT_DCB_CCB Ccb, IN PIRP Irp );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, MsCommonDirectoryControl )
#pragma alloc_text( PAGE, MsFsdDirectoryControl )
#pragma alloc_text( PAGE, MsQueryDirectory )
#endif
NTSTATUS MsFsdDirectoryControl ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine is the FSD routine that handles directory control functions (i.e., query and notify).
Arguments:
MsfsDeviceObject - Supplies the device object for the directory function.
Irp - Supplies the IRP to process.
Return Value:
NTSTATUS - The result status.
--*/
{ NTSTATUS status;
PAGED_CODE(); DebugTrace(+1, Dbg, "MsFsdDirectoryControl\n", 0);
//
// Call the common direcotry control routine.
//
FsRtlEnterFileSystem();
status = MsCommonDirectoryControl( MsfsDeviceObject, Irp );
FsRtlExitFileSystem(); //
// Return to the caller.
//
DebugTrace(-1, Dbg, "MsFsdDirectoryControl -> %08lx\n", status );
return status; }
VOID MsFlushNotifyForFile ( IN PDCB Dcb, IN PFILE_OBJECT FileObject ) /*++
Routine Description:
This routine checks the notify queues of a DCB and completes any outstanding IRPS that match the given file object. This is used at cleanup time.
Arguments:
Dcb - Supplies the DCB to check for outstanding notify IRPs.
FileObject - File object that IRP must be associated with.
Return Value:
None.
--*/ { PLIST_ENTRY Links; PIRP Irp; KIRQL OldIrql; PLIST_ENTRY Head; PIO_STACK_LOCATION IrpSp; LIST_ENTRY CompletionList;
Head = &Dcb->Specific.Dcb.NotifyFullQueue;
InitializeListHead (&CompletionList);
KeAcquireSpinLock (&Dcb->Specific.Dcb.SpinLock, &OldIrql);
Links = Head->Flink; while (1) {
if (Links == Head) { //
// We are at the end of this queue.
//
if (Head == &Dcb->Specific.Dcb.NotifyFullQueue) { Head = &Dcb->Specific.Dcb.NotifyPartialQueue; Links = Head->Flink; if (Links == Head) { break; } } else { break; } }
Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry ); IrpSp = IoGetCurrentIrpStackLocation( Irp );
//
// If this IRP is for the matching file object then remove and save for completion
//
if (IrpSp->FileObject == FileObject) {
Links = Links->Flink;
RemoveEntryList (&Irp->Tail.Overlay.ListEntry); //
// Remove cancel routine and detect if its already started running
//
if (IoSetCancelRoutine (Irp, NULL)) { //
// Cancel isn't active and won't become active.
//
InsertTailList (&CompletionList, &Irp->Tail.Overlay.ListEntry);
} else { //
// Cancel is already active but is stalled before lock acquire. Initialize the
// list head so the second remove is a noop. This is a rare case.
//
InitializeListHead (&Irp->Tail.Overlay.ListEntry); } } else { Links = Links->Flink; }
} KeReleaseSpinLock (&Dcb->Specific.Dcb.SpinLock, OldIrql);
while (!IsListEmpty (&CompletionList)) {
Links = RemoveHeadList (&CompletionList); Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry ); MsCompleteRequest( Irp, STATUS_CANCELLED );
}
return; }
VOID MsCheckForNotify ( IN PDCB Dcb, IN BOOLEAN CheckAllOutstandingIrps, IN NTSTATUS FinalStatus )
/*++
Routine Description:
This routine checks the notify queues of a DCB and completes any outstanding IRPS.
Note that the caller of this procedure must guarantee that the DCB is acquired for exclusive access.
Arguments:
Dcb - Supplies the DCB to check for outstanding notify IRPs.
CheckAllOutstandingIrps - Indicates if only the NotifyFullQueue should be checked. If TRUE then all notify queues are checked, and if FALSE then only the NotifyFullQueue is checked.
Return Value:
None.
--*/
{ PLIST_ENTRY links; PIRP irp; KIRQL OldIrql; PLIST_ENTRY Head;
//
// We'll always signal the notify full queue entries. They want
// to be notified if every any change is made to a directory.
//
Head = &Dcb->Specific.Dcb.NotifyFullQueue;
KeAcquireSpinLock (&Dcb->Specific.Dcb.SpinLock, &OldIrql);
while (1) {
links = RemoveHeadList (Head); if (links == Head) { //
// This queue is empty. See if we need to skip to another.
//
if (Head == &Dcb->Specific.Dcb.NotifyFullQueue && CheckAllOutstandingIrps) { Head = &Dcb->Specific.Dcb.NotifyPartialQueue; links = RemoveHeadList (Head); if (links == Head) { break; } } else { break; } } //
// Remove the Irp from the head of the queue, and complete it
// with a success status.
//
irp = CONTAINING_RECORD( links, IRP, Tail.Overlay.ListEntry );
//
// Remove cancel routine and detect if its already started running
//
if (IoSetCancelRoutine (irp, NULL)) { //
// Cancel isn't active and won't become active. Release the spinlock for the complete.
//
KeReleaseSpinLock (&Dcb->Specific.Dcb.SpinLock, OldIrql);
MsCompleteRequest( irp, FinalStatus );
KeAcquireSpinLock (&Dcb->Specific.Dcb.SpinLock, &OldIrql); } else { //
// Cancel is already active but is stalled before lock acquire. Initialize the
// list head so the second remove is a noop. This is a rare case.
//
InitializeListHead (&irp->Tail.Overlay.ListEntry); } } KeReleaseSpinLock (&Dcb->Specific.Dcb.SpinLock, OldIrql);
return; }
NTSTATUS MsCommonDirectoryControl ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine does the common code for directory control functions.
Arguments:
MsfsDeviceObject - Supplies the mailslot device object.
Irp - Supplies the Irp being processed.
Return Value:
NTSTATUS - The return status for the operation
--*/
{ NTSTATUS status;
PIO_STACK_LOCATION irpSp;
NODE_TYPE_CODE nodeTypeCode; PROOT_DCB_CCB ccb; PROOT_DCB rootDcb;
PAGED_CODE();
//
// Get the current stack location
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "CommonDirectoryControl...\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp);
//
// Decode the file object to figure out who we are. If the result
// is not the root DCB then its an illegal parameter.
//
if ((nodeTypeCode = MsDecodeFileObject( irpSp->FileObject, (PVOID *)&rootDcb, (PVOID *)&ccb )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Not a directory\n", 0);
MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); status = STATUS_INVALID_PARAMETER;
DebugTrace(-1, Dbg, "CommonDirectoryControl -> %08lx\n", status ); return status; }
if (nodeTypeCode != MSFS_NTC_ROOT_DCB) {
DebugTrace(0, Dbg, "Not a directory\n", 0); MsDereferenceNode( &rootDcb->Header );
MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); status = STATUS_INVALID_PARAMETER;
DebugTrace(-1, Dbg, "CommonDirectoryControl -> %08lx\n", status ); return status; }
//
// Acquire exclusive access to the root DCB.
//
MsAcquireExclusiveFcb( (PFCB)rootDcb );
//
// Check if its been cleaned up yet.
//
status = MsVerifyDcbCcb (ccb);
if (NT_SUCCESS (status)) { //
// We know this is a directory control so we'll case on the
// minor function, and call the appropriate work routines.
//
switch (irpSp->MinorFunction) {
case IRP_MN_QUERY_DIRECTORY:
status = MsQueryDirectory( rootDcb, ccb, Irp ); break;
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
status = MsNotifyChangeDirectory( rootDcb, ccb, Irp ); break;
default:
//
// For all other minor function codes we say they're invalid
// and complete the request.
//
DebugTrace(0, DEBUG_TRACE_ERROR, "Invalid FS Control Minor Function Code %08lx\n", irpSp->MinorFunction);
status = STATUS_INVALID_DEVICE_REQUEST; break; }
}
MsReleaseFcb( (PFCB)rootDcb );
MsDereferenceRootDcb( rootDcb );
if (status != STATUS_PENDING) { MsCompleteRequest( Irp, status ); }
return status; }
NTSTATUS MsQueryDirectory ( IN PROOT_DCB RootDcb, IN PROOT_DCB_CCB Ccb, IN PIRP Irp )
/*++
Routine Description:
This is the work routine for querying a directory.
Arugments:
RootDcb - Supplies the dcb being queried
Ccb - Supplies the context of the caller
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The return status for the operation.
--*/
{ NTSTATUS status; PIO_STACK_LOCATION irpSp;
PUCHAR buffer; CLONG systemBufferLength; UNICODE_STRING fileName; ULONG fileIndex; FILE_INFORMATION_CLASS fileInformationClass; BOOLEAN restartScan; BOOLEAN returnSingleEntry; BOOLEAN indexSpecified;
#if 0
UNICODE_STRING unicodeString; ULONG unicodeStringLength; #endif
BOOLEAN ansiStringAllocated = FALSE;
static WCHAR star = L'*';
BOOLEAN caseInsensitive = TRUE; //*** Make searches case insensitive
ULONG currentIndex;
ULONG lastEntry; ULONG nextEntry;
PLIST_ENTRY links; PFCB fcb;
PFILE_DIRECTORY_INFORMATION dirInfo; PFILE_NAMES_INFORMATION namesInfo;
PAGED_CODE();
//
// Get the current stack location.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "MsQueryDirectory\n", 0 ); DebugTrace( 0, Dbg, "RootDcb = %08lx\n", (ULONG)RootDcb); DebugTrace( 0, Dbg, "Ccb = %08lx\n", (ULONG)Ccb); DebugTrace( 0, Dbg, "SystemBuffer = %08lx\n", (ULONG)Irp->AssociatedIrp.SystemBuffer); DebugTrace( 0, Dbg, "Length = %08lx\n", irpSp->Parameters.QueryDirectory.Length); DebugTrace( 0, Dbg, "FileName = %08lx\n", (ULONG)irpSp->Parameters.QueryDirectory.FileName); DebugTrace( 0, Dbg, "FileIndex = %08lx\n", irpSp->Parameters.QueryDirectory.FileIndex); DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", irpSp->Parameters.QueryDirectory.FileInformationClass); DebugTrace( 0, Dbg, "RestartScan = %08lx\n", FlagOn(irpSp->Flags, SL_RESTART_SCAN)); DebugTrace( 0, Dbg, "ReturnSingleEntry = %08lx\n", FlagOn(irpSp->Flags, SL_RETURN_SINGLE_ENTRY)); DebugTrace( 0, Dbg, "IndexSpecified = %08lx\n", FlagOn(irpSp->Flags, SL_INDEX_SPECIFIED));
//
// Make local copies of the input parameters.
//
systemBufferLength = irpSp->Parameters.QueryDirectory.Length;
fileIndex = irpSp->Parameters.QueryDirectory.FileIndex; fileInformationClass = irpSp->Parameters.QueryDirectory.FileInformationClass;
restartScan = FlagOn(irpSp->Flags, SL_RESTART_SCAN); indexSpecified = FlagOn(irpSp->Flags, SL_INDEX_SPECIFIED); returnSingleEntry = FlagOn(irpSp->Flags, SL_RETURN_SINGLE_ENTRY);
if (irpSp->Parameters.QueryDirectory.FileName != NULL) {
fileName = *(PUNICODE_STRING)irpSp->Parameters.QueryDirectory.FileName;
//
// Ensure that the name is reasonable
//
if( (fileName.Buffer == NULL && fileName.Length) || FlagOn( fileName.Length, 1 ) ) {
status = STATUS_OBJECT_NAME_INVALID; return status; }
} else {
fileName.Length = 0; fileName.Buffer = NULL;
}
//
// Check if the CCB already has a query template attached. If it
// does not already have one then we either use the string we are
// given or we attach our own containing "*"
//
if (Ccb->QueryTemplate == NULL) {
//
// This is our first time calling query directory so we need
// to either set the query template to the user specified string
// or to "*".
//
if (fileName.Buffer == NULL) {
DebugTrace(0, Dbg, "Set template to *\n", 0);
fileName.Length = sizeof( WCHAR ); fileName.Buffer = ☆ }
DebugTrace(0, Dbg, "Set query template -> %wZ\n", (ULONG)&fileName);
//
// Allocate space for the query template.
//
Ccb->QueryTemplate = MsAllocatePagedPoolWithQuota ( sizeof(UNICODE_STRING) + fileName.Length, 'tFsM' );
if (Ccb->QueryTemplate == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; return status; }
//
// Initialize the query template and copy over the string.
//
Ccb->QueryTemplate->Length = fileName.Length; Ccb->QueryTemplate->Buffer = (PWCH)((PSZ)Ccb->QueryTemplate + sizeof(UNICODE_STRING));
RtlCopyMemory (Ccb->QueryTemplate->Buffer, fileName.Buffer, fileName.Length);
//
// Set the search to start at the beginning of the directory.
//
fileIndex = 0;
} else {
//
// Check if we were given an index to start with or if we need to
// restart the scan or if we should use the index that was saved in
// the CCB.
//
if (restartScan) {
fileIndex = 0;
} else if (!indexSpecified) {
fileIndex = Ccb->IndexOfLastCcbReturned + 1; }
}
//
// Now we are committed to completing the Irp, we do that in
// the finally clause of the following try.
//
try {
ULONG baseLength; ULONG lengthAdded; BOOLEAN Match;
//
// Map the user buffer.
//
MsMapUserBuffer( Irp, KernelMode, (PVOID *)&buffer );
//
// At this point we are about to enter our query loop. We have
// already decided which Fcb index we need to return. The variables
// LastEntry and NextEntry are used to index into the user buffer.
// LastEntry is the last entry we added to the user buffer, and
// NextEntry is the current one we're working on. CurrentIndex
// is the Fcb index that we are looking at next. Logically the
// way the loop works is as follows.
//
// Scan all of the Fcb in the directory
//
// if the Fcb matches the query template then
//
// if the CurrentIndex is >= the FileIndex then
//
// process this fcb, and decide if we should
// continue the main loop
//
// end if
//
// Increment the current index
//
// end if
//
// end scan
//
currentIndex = 0;
lastEntry = 0; nextEntry =0;
switch (fileInformationClass) {
case FileDirectoryInformation:
baseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); break;
case FileFullDirectoryInformation:
baseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); break;
case FileNamesInformation:
baseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); break;
case FileBothDirectoryInformation:
baseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); break;
default:
try_return( status = STATUS_INVALID_INFO_CLASS ); }
for (links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink; links != &RootDcb->Specific.Dcb.ParentDcbQueue; links = links->Flink) {
fcb = CONTAINING_RECORD(links, FCB, ParentDcbLinks);
ASSERT(fcb->Header.NodeTypeCode == MSFS_NTC_FCB);
DebugTrace(0, Dbg, "Top of Loop\n", 0); DebugTrace(0, Dbg, "Fcb = %08lx\n", (ULONG)fcb); DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", currentIndex); DebugTrace(0, Dbg, "FileIndex = %08lx\n", fileIndex); DebugTrace(0, Dbg, "LastEntry = %08lx\n", lastEntry); DebugTrace(0, Dbg, "NextEntry = %08lx\n", nextEntry);
//
// Check if the Fcb represents a mailslot that is part of
// our query template.
//
try { Match = FsRtlIsNameInExpression( Ccb->QueryTemplate, &fcb->LastFileName, caseInsensitive, NULL ); } except (EXCEPTION_EXECUTE_HANDLER) { try_return (status = GetExceptionCode ()); }
if (Match) {
//
// The FCB is in the query template so now check if
// this is the index we should start returning.
//
if (currentIndex >= fileIndex) {
//
// Yes it is one to return so case on the requested
// information class.
//
ULONG bytesToCopy; ULONG bytesRemainingInBuffer;
//
// Here are the rules concerning filling up the buffer:
//
// 1. The Io system garentees that there will always be
// enough room for at least one base record.
//
// 2. If the full first record (including file name) cannot
// fit, as much of the name as possible is copied and
// STATUS_BUFFER_OVERFLOW is returned.
//
// 3. If a subsequent record cannot completely fit into the
// buffer, none of it (as in 0 bytes) is copied, and
// STATUS_SUCCESS is returned. A subsequent query will
// pick up with this record.
//
bytesRemainingInBuffer = systemBufferLength - nextEntry;
if ( (nextEntry != 0) && ( (baseLength + fcb->LastFileName.Length > bytesRemainingInBuffer) || (systemBufferLength < nextEntry) ) ) {
DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
try_return( status = STATUS_SUCCESS ); }
ASSERT( bytesRemainingInBuffer >= baseLength );
//
// See how much of the name we will be able to copy into
// the system buffer. This also dictates out return
// value.
//
if ( baseLength + fcb->LastFileName.Length <= bytesRemainingInBuffer ) {
bytesToCopy = fcb->LastFileName.Length; status = STATUS_SUCCESS;
} else {
bytesToCopy = bytesRemainingInBuffer - baseLength; status = STATUS_BUFFER_OVERFLOW; }
//
// Note how much of buffer we are consuming and zero
// the base part of the structure.
//
lengthAdded = baseLength + bytesToCopy;
try {
RtlZeroMemory( &buffer[nextEntry], baseLength );
switch (fileInformationClass) {
case FileBothDirectoryInformation:
//
// We don't need short name
//
DebugTrace(0, Dbg, "Getting directory full information\n", 0);
case FileFullDirectoryInformation:
//
// We don't use EaLength, so fill in nothing here.
//
DebugTrace(0, Dbg, "Getting directory full information\n", 0);
case FileDirectoryInformation:
DebugTrace(0, Dbg, "Getting directory information\n", 0);
//
// The eof indicates the number of instances and
// allocation size is the maximum allowed
//
dirInfo = (PFILE_DIRECTORY_INFORMATION)&buffer[nextEntry];
dirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
dirInfo->CreationTime = fcb->Specific.Fcb.CreationTime; dirInfo->LastAccessTime = fcb->Specific.Fcb.LastAccessTime; dirInfo->LastWriteTime = fcb->Specific.Fcb.LastModificationTime; dirInfo->ChangeTime = fcb->Specific.Fcb.LastChangeTime;
dirInfo->FileNameLength = fcb->LastFileName.Length;
break;
case FileNamesInformation:
DebugTrace(0, Dbg, "Getting names information\n", 0);
namesInfo = (PFILE_NAMES_INFORMATION)&buffer[nextEntry];
namesInfo->FileNameLength = fcb->LastFileName.Length;
break;
default:
KeBugCheck( MAILSLOT_FILE_SYSTEM ); }
RtlCopyMemory (&buffer[nextEntry + baseLength], fcb->LastFileName.Buffer, bytesToCopy);
//
// Update the CCB to the index we've just used.
//
Ccb->IndexOfLastCcbReturned = currentIndex;
//
// And indicate how much of the system buffer we have
// currently used up. We must compute this value before
// we long align outselves for the next entry.
//
Irp->IoStatus.Information = nextEntry + lengthAdded;
//
// Setup the previous next entry offset.
//
*((PULONG)(&buffer[lastEntry])) = nextEntry - lastEntry;
} except( EXCEPTION_EXECUTE_HANDLER ) {
status = GetExceptionCode(); try_return( status ); }
//
// Check if the last entry didn't completely fit
//
if ( status == STATUS_BUFFER_OVERFLOW ) {
try_return( NOTHING ); }
//
// Check if we are only to return a single entry
//
if (returnSingleEntry) {
try_return( status = STATUS_SUCCESS ); }
//
// Set ourselves up for the next iteration
//
lastEntry = nextEntry; nextEntry += (ULONG)QuadAlign( lengthAdded ); }
//
// Increment the current index by one
//
currentIndex += 1; } }
//
// At this point we've scanned the entire list of FCBs so if
// the NextEntry is zero then we haven't found anything so we
// will return no more files, otherwise we return success.
//
if (nextEntry == 0) { status = STATUS_NO_MORE_FILES; } else { status = STATUS_SUCCESS; }
try_exit: NOTHING; } finally {
DebugTrace(-1, Dbg, "MsQueryDirectory -> %08lx\n", status); }
return status; }
VOID MsNotifyChangeDirectoryCancel ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
This is the cancel routine for the directory notify request.
Arugments:
DeviceObject - Supplies the device object for the request being canceled.
Irp - Supplies the Irp being canceled.
Return Value:
None --*/
{ KIRQL OldIrql; PKSPIN_LOCK pSpinLock;
//
// First drop the cancel spinlock. We don't use this for this path
//
IoReleaseCancelSpinLock (Irp->CancelIrql);
//
// Grab the spinlock address. Easier that tracing the pointers or assuming that there is
// only one DCB
//
pSpinLock = Irp->Tail.Overlay.DriverContext[0]; //
// Acquire the spinlock protecting these queues.
//
KeAcquireSpinLock (pSpinLock, &OldIrql);
//
// Remove the entry from the list. We will always be in one of the lists or this entry has
// been initializes as an empty list by one of the completion routines when it detected
// this routine was active.
//
RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock (pSpinLock, OldIrql);
//
// Complete the IRP
//
MsCompleteRequest( Irp, STATUS_CANCELLED );
return; }
NTSTATUS MsNotifyChangeDirectory ( IN PROOT_DCB RootDcb, IN PROOT_DCB_CCB Ccb, IN PIRP Irp )
/*++
Routine Description:
This is the common routine for doing the notify change directory.
Arugments:
RootDcb - Supplies the DCB being queried.
Ccb - Supplies the context of the caller.
Irp - Supplies the Irp being processed.
Return Value:
NTSTATUS - STATUS_PENDING or STATUS_CANCELLED
--*/
{ PIO_STACK_LOCATION irpSp; NTSTATUS Status; KIRQL OldIrql; PLIST_ENTRY Head;
//
// Get the current stack location.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "MsNotifyChangeDirectory\n", 0 ); DebugTrace( 0, Dbg, "RootDcb = %p", RootDcb); DebugTrace( 0, Dbg, "Ccb = %p", Ccb);
//
// Mark the Irp pending.
//
if (irpSp->Parameters.NotifyDirectory.CompletionFilter & (~FILE_NOTIFY_CHANGE_NAME)) { Head = &RootDcb->Specific.Dcb.NotifyFullQueue; } else { Head = &RootDcb->Specific.Dcb.NotifyPartialQueue; } //
// Make it easy for the cancel routine to find this spinlock
//
Irp->Tail.Overlay.DriverContext[0] = &RootDcb->Specific.Dcb.SpinLock; //
// Acquire the spinlock protecting these queues.
//
KeAcquireSpinLock (&RootDcb->Specific.Dcb.SpinLock, &OldIrql); IoSetCancelRoutine (Irp, MsNotifyChangeDirectoryCancel); //
// See if the IRP was already canceled before we enabled cancelation
//
if (Irp->Cancel && IoSetCancelRoutine (Irp, NULL) != NULL) {
KeReleaseSpinLock (&RootDcb->Specific.Dcb.SpinLock, OldIrql); Status = STATUS_CANCELLED;
} else {
IoMarkIrpPending( Irp ); InsertTailList( Head, &Irp->Tail.Overlay.ListEntry ); KeReleaseSpinLock (&RootDcb->Specific.Dcb.SpinLock, OldIrql); Status = STATUS_PENDING;
}
//
// Return to our caller.
//
DebugTrace(-1, Dbg, "NotifyChangeDirectory status %X\n", Status);
return Status; }
|