895 lines
23 KiB
C
895 lines
23 KiB
C
|
/*++
|
|||
|
|
|||
|
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, MsCheckForNotify )
|
|||
|
#pragma alloc_text( PAGE, MsCommonDirectoryControl )
|
|||
|
#pragma alloc_text( PAGE, MsFsdDirectoryControl )
|
|||
|
#pragma alloc_text( PAGE, MsNotifyChangeDirectory )
|
|||
|
#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.
|
|||
|
//
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
status = MsCommonDirectoryControl( MsfsDeviceObject, Irp );
|
|||
|
|
|||
|
} except(MsExceptionFilter( GetExceptionCode() )) {
|
|||
|
|
|||
|
//
|
|||
|
// We had some trouble trying to perform the requested
|
|||
|
// operation, so we'll abort the I/O request with
|
|||
|
// the error status that we get back from the
|
|||
|
// execption code.
|
|||
|
//
|
|||
|
|
|||
|
status = MsProcessException( MsfsDeviceObject, Irp, GetExceptionCode() );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return to the caller.
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "MsFsdDirectoryControl -> %08lx\n", status );
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
MsCheckForNotify (
|
|||
|
IN PDCB Dcb,
|
|||
|
IN BOOLEAN CheckAllOutstandingIrps
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// We'll always signal the notify full queue entries. They want
|
|||
|
// to be notified if every any change is made to a directory.
|
|||
|
//
|
|||
|
|
|||
|
while (!IsListEmpty( &Dcb->Specific.Dcb.NotifyFullQueue )) {
|
|||
|
|
|||
|
//
|
|||
|
// Remove the Irp from the head of the queue, and complete it
|
|||
|
// with a success status.
|
|||
|
//
|
|||
|
|
|||
|
links = RemoveHeadList( &Dcb->Specific.Dcb.NotifyFullQueue );
|
|||
|
irp = CONTAINING_RECORD( links, IRP, Tail.Overlay.ListEntry );
|
|||
|
MsCompleteRequest( irp, STATUS_SUCCESS );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now check if we should also do the partial notify queue.
|
|||
|
//
|
|||
|
|
|||
|
if (CheckAllOutstandingIrps) {
|
|||
|
|
|||
|
while (!IsListEmpty( &Dcb->Specific.Dcb.NotifyPartialQueue )) {
|
|||
|
|
|||
|
//
|
|||
|
// Remove the Irp from the head of the queue, and complete it
|
|||
|
// with a success status.
|
|||
|
//
|
|||
|
|
|||
|
links = RemoveHeadList( &Dcb->Specific.Dcb.NotifyPartialQueue );
|
|||
|
irp = CONTAINING_RECORD( links, IRP, Tail.Overlay.ListEntry );
|
|||
|
MsCompleteRequest( irp, STATUS_SUCCESS );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
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);
|
|||
|
MsDereferenceRootDcb( rootDcb );
|
|||
|
|
|||
|
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 );
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// 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);
|
|||
|
|
|||
|
MsCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST );
|
|||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} finally {
|
|||
|
|
|||
|
MsReleaseFcb( (PFCB)rootDcb );
|
|||
|
MsDereferenceRootDcb( rootDcb );
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "CommonDirectoryControl -> %08lx\n", 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;
|
|||
|
|
|||
|
} 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 = FsRtlAllocatePool(
|
|||
|
PagedPool,
|
|||
|
sizeof(UNICODE_STRING) + fileName.Length
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the query template and copy over the string.
|
|||
|
//
|
|||
|
|
|||
|
Ccb->QueryTemplate->Length = fileName.Length;
|
|||
|
Ccb->QueryTemplate->Buffer = (PWCH)((PSZ)Ccb->QueryTemplate + sizeof(UNICODE_STRING));
|
|||
|
|
|||
|
RtlMoveMemory( Ccb->QueryTemplate->Buffer,
|
|||
|
fileName.Buffer,
|
|||
|
fileName.Length );
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Now zero out the file name so we won't think we're to use it
|
|||
|
// as a subsearch string
|
|||
|
//
|
|||
|
|
|||
|
fileName.Length = 0;
|
|||
|
fileName.Buffer = NULL;
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
|
|||
|
if (FsRtlIsNameInExpression( Ccb->QueryTemplate,
|
|||
|
&fcb->LastFileName,
|
|||
|
caseInsensitive,
|
|||
|
NULL )) {
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
|
|||
|
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 );
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory( &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;
|
|||
|
|
|||
|
//
|
|||
|
// 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 {
|
|||
|
|
|||
|
MsCompleteRequest( Irp, status );
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "MsQueryDirectory -> %08lx\n", status);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Get the current stack location.
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "MsNotifyChangeDirectory\n", 0 );
|
|||
|
DebugTrace( 0, Dbg, "RootDcb = %08lx", (ULONG)RootDcb);
|
|||
|
DebugTrace( 0, Dbg, "Ccb = %08lx", (ULONG)Ccb);
|
|||
|
|
|||
|
//
|
|||
|
// Mark the Irp pending.
|
|||
|
//
|
|||
|
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG - For now, simply place the packet on one of the old queues,
|
|||
|
// full or partial, based on whether or not changes to anything
|
|||
|
// other than names were requested. In the future, the filter
|
|||
|
// must actually be implemented.
|
|||
|
//
|
|||
|
|
|||
|
if (irpSp->Parameters.NotifyDirectory.CompletionFilter &
|
|||
|
~FILE_NOTIFY_CHANGE_NAME) {
|
|||
|
|
|||
|
InsertTailList( &RootDcb->Specific.Dcb.NotifyFullQueue,
|
|||
|
&Irp->Tail.Overlay.ListEntry );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
InsertTailList( &RootDcb->Specific.Dcb.NotifyPartialQueue,
|
|||
|
&Irp->Tail.Overlay.ListEntry );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return to our caller a value of status pending.
|
|||
|
//
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "NotifyChangeDirectory -> STATUS_PENDING\n", 0);
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|