Filtering IRP_MJ_DIRECTORY_CONTROL (QueryDirectory)

Hi

I am in the middle of writing a filter driver that filters calls from the
C:\ drive to the N:\ drive for legacy applications which don’t include
network support.

So basically if the program asks for a list of files in C:\Test then files
that are in C:\Test are displayed, and those (that aren’t already in the
C:\Test directory) in N:\Test are also displayed.

To do this I have hooked the device object, and process the
IRP_MJ_DIRECTORY_CONTROL message. The first message I get for a new
directory listing allocates some memory internally to store the network
directory and then passes the call onto the intended device driver with
IoCallDriver (). I set up a completion routine for calls to
IRP_MJ_DIRECTORY_CONTROL and the code is below.

The files I add at the end of the buffer if there is room appear in the
directory listing, but the ones I add after the STATUS_NO_MORE_FILES is
detected aren’t, and I don’t get any more requests. I assumed as I was
changing the return code to STATUS_SUCCESS and filling in the buffer
length, that it would request more files.

Does anybody know if anything else is being modified which is stopping the
search?

Any information would be greatly appreciated.

Phil Lawson

NTSTATUS RMFilterNetworkDone
(
PDEVICE_OBJECT pDeviceObject_,
PIRP pIrp_,
PVOID pContext_
)

{
PQUERY_DIRECTORY pQuery;
PIO_STACK_LOCATION pIoStackLocation;

// A request completed - look at the result
pIoStackLocation = IoGetCurrentIrpStackLocation (pIrp_);
pQuery = (PQUERY_DIRECTORY) &pIoStackLocation->Parameters.Read;

// When the request for files in a directory ends, we step in
// and fill in any extra files that may be rquired. We then return
// STATUS_SUCCESS and fill the Information field with the number of
// bytes of date we have copied
if (pIrp_->IoStatus.Status == STATUS_NO_MORE_FILES)
{
// Add the files
AddNetworkFiles (pIrp_);

// Clean up
if (pIrp_->IoStatus.Information)
{
PFILE_BOTH_DIR_INFORMATION pInfo = pIrp_->IoStatus.Status =
pIrp_->UserIosb->Status = STATUS_SUCCESS;

pIrp_->UserIosb->Information = pIrp_->IoStatus.Information;
}
else
{
// We must have added all the additional files, so we can free
// the memory we allocated to store the network file directory
ExFreePool (g_pNetworkBuffer);
g_pNetworkBuffer = NULL;
g_fulBufferType = 0L;
g_ulIrpBufferLength = 0L;
}
}
else
{
// We are still returning entries that are actually files in
// the directory requested. We need to search through the
// network directory list looking for matches. If there is a
// match then we flag that the file is already in the list
char* pData = pIrp_->UserBuffer;
PFILE_BOTH_DIR_INFORMATION pInfo = (PFILE_BOTH_DIR_INFORMATION)pData;

while (TRUE)
{
PCHAR pNetDir = g_pNetworkBuffer;
PFILE_BOTH_DIR_INFORMATION pNetwork = (PFILE_BOTH_DIR_INFORMATION)
pNetDir;

// Iterate through our network files and see if we have a match
while (TRUE)
{
// If we have a match, mark the netwrok file so that it is not added
// again at the end when we add the network files
if (wcsncmp (pInfo->FileName, pNetwork->FileName, pInfo->FileNameLength /
sizeof (WCHAR)) == 0)
{
pNetwork->FileIndex = (ULONG) -1;
break;
}

// Break out of the loop if the next entry is not valid
if (pNetwork->NextEntryOffset == 0)
break;

// Increment the network pointers
pNetDir += pNetwork->NextEntryOffset;
pNetwork = (PFILE_BOTH_DIR_INFORMATION) pNetDir;
}

// Jump out of the loop if the next entry is not valid
if (pInfo->NextEntryOffset == 0)
break;

// Increment the variables
pData += pInfo->NextEntryOffset;
pInfo = (PFILE_BOTH_DIR_INFORMATION) pData;
}

// We may be able to add some files to this buffer
if (pIrp_->IoStatus.Information < g_ulIrpBufferLength &&
!(pIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY))
{
AddNetworkFiles (pIrp_);
}
}

// Now we have to mark Irp as pending if necessary
if (pIrp_->PendingReturned)
{
IoMarkIrpPending (pIrp_);
}

// Return the status
return pIrp_->IoStatus.Status;
}

Hi,

You can’t change pIrp->IoStatus.Status in completion routine. Completion
routine must return STATUS_SUCCESS or
STATUS_MORE_PROCESSING_REQUIRED. To do what you want you need create your
own IRP, set completion
routine for this IRP that will signal some event
STATUS_MORE_PROCESSING_REQUIRED and send it to file system.
In your dispatch routine you will wait for this event, then fill original
IRP the way you want and complete it with appropriate status.

Best regards,
Alexei.


From: PHIL LAWSON
> To: File Systems Developers
> Subject: [ntfsd] Filtering IRP_MJ_DIRECTORY_CONTROL (QueryDirectory)
> Date: Wednesday, April 19, 2000 3:52 AM
>
> Hi
>
> I am in the middle of writing a filter driver that filters calls from the

> C:\ drive to the N:\ drive for legacy applications which don’t include
> network support.
>
> So basically if the program asks for a list of files in C:\Test then
files
> that are in C:\Test are displayed, and those (that aren’t already in the
> C:\Test directory) in N:\Test are also displayed.
>
> To do this I have hooked the device object, and process the
> IRP_MJ_DIRECTORY_CONTROL message. The first message I get for a new
> directory listing allocates some memory internally to store the network
> directory and then passes the call onto the intended device driver with
> IoCallDriver (). I set up a completion routine for calls to
> IRP_MJ_DIRECTORY_CONTROL and the code is below.
>
> The files I add at the end of the buffer if there is room appear in the
> directory listing, but the ones I add after the STATUS_NO_MORE_FILES is
> detected aren’t, and I don’t get any more requests. I assumed as I was
> changing the return code to STATUS_SUCCESS and filling in the buffer
> length, that it would request more files.
>
> Does anybody know if anything else is being modified which is stopping
the
> search?
>
> Any information would be greatly appreciated.
>
> Phil Lawson
>
>
> NTSTATUS RMFilterNetworkDone
> (
> PDEVICE_OBJECT pDeviceObject_,
> PIRP pIrp_,
> PVOID pContext_
> )
>
> {
> PQUERY_DIRECTORY pQuery;
> PIO_STACK_LOCATION pIoStackLocation;
>
> // A request completed - look at the result
> pIoStackLocation = IoGetCurrentIrpStackLocation (pIrp_);
> pQuery = (PQUERY_DIRECTORY) &pIoStackLocation->Parameters.Read;
>
> // When the request for files in a directory ends, we step in
> // and fill in any extra files that may be rquired. We then return
> // STATUS_SUCCESS and fill the Information field with the number of
> // bytes of date we have copied
> if (pIrp_->IoStatus.Status == STATUS_NO_MORE_FILES)
> {
> // Add the files
> AddNetworkFiles (pIrp_);
>
> // Clean up
> if (pIrp_->IoStatus.Information)
> {
> PFILE_BOTH_DIR_INFORMATION pInfo = pIrp_->IoStatus.Status =
> pIrp_->UserIosb->Status = STATUS_SUCCESS;
>
> pIrp_->UserIosb->Information = pIrp_->IoStatus.Information;
> }
> else
> {
> // We must have added all the additional files, so we can free
> // the memory we allocated to store the network file
directory
> ExFreePool (g_pNetworkBuffer);
> g_pNetworkBuffer = NULL;
> g_fulBufferType = 0L;
> g_ulIrpBufferLength = 0L;
> }
> }
> else
> {
> // We are still returning entries that are actually files in
> // the directory requested. We need to search through the
> // network directory list looking for matches. If there is a
> // match then we flag that the file is already in the list
> char* pData = pIrp_->UserBuffer;
> PFILE_BOTH_DIR_INFORMATION pInfo = (PFILE_BOTH_DIR_INFORMATION)pData;
>
> while (TRUE)
> {
> PCHAR pNetDir = g_pNetworkBuffer;
> PFILE_BOTH_DIR_INFORMATION pNetwork = (PFILE_BOTH_DIR_INFORMATION)
> pNetDir;
>
> // Iterate through our network files and see if we have a match
> while (TRUE)
> {
> // If we have a match, mark the netwrok file so that it is not added
> // again at the end when we add the network files
> if (wcsncmp (pInfo->FileName, pNetwork->FileName, pInfo->FileNameLength
/
> sizeof (WCHAR)) == 0)
> {
> pNetwork->FileIndex = (ULONG) -1;
> break;
> }
>
> // Break out of the loop if the next entry is not valid
> if (pNetwork->NextEntryOffset == 0)
> break;
>
> // Increment the network pointers
> pNetDir += pNetwork->NextEntryOffset;
> pNetwork = (PFILE_BOTH_DIR_INFORMATION) pNetDir;
> }
>
> // Jump out of the loop if the next entry is not valid
> if (pInfo->NextEntryOffset == 0)
> break;
>
> // Increment the variables
> pData += pInfo->NextEntryOffset;
> pInfo = (PFILE_BOTH_DIR_INFORMATION) pData;
> }
>
> // We may be able to add some files to this buffer
> if (pIrp_->IoStatus.Information < g_ulIrpBufferLength &&
> !(pIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY))
> {
> AddNetworkFiles (pIrp_);
> }
> }
>
>
> // Now we have to mark Irp as pending if necessary
> if (pIrp_->PendingReturned)
> {
> IoMarkIrpPending (pIrp_);
> }
>
> // Return the status
> return pIrp_->IoStatus.Status;
> }
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@mondenet.com
> To unsubscribe send a blank email to $subst(‘Email.Unsub’)