Because if you call it with APCs disabled and the highest level driver marks the IRP as pending and returns STATUS_PENDING it will never complete - because the completion logic queues an APC object (it’s in the IRP actually) to indicate the completion status and clean up the IRP, but because you have blocked special kernel APCs the APC sits on the queue and the thread never unblocks.
If you are a kernel driver and send an IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY at APC level it won’t matter because YOU have provided a completion routine - which gets invoked. There’s no APC involved. Thus, it won’t hang.
In fact, if you DO call ZwQueryDirectoryFile it will work as long as the highest level driver doesn’t mark the IRP as pending and return STATUS_PENDING. So this is a subtle bug that you might never notice during testing.
If you look at the FasFat code, in FatQueryDirectory (dirctrl.c), you can see at least one path where this might happen:
if (InitialQuery || RestartScan) {
if (!FatAcquireExclusiveFcb( IrpContext, Dcb )) {
DebugTrace(0, Dbg, “FatQueryDirectory -> Enqueue to Fsp\n”, 0);
Status = FatFsdPostRequest( IrpContext, Irp );
DebugTrace(-1, Dbg, “FatQueryDirectory -> %08lx\n”, Status);
return Status;
}
// …
FatFsdPostRequest will return STATUS_PENDING (see workqueue.c):
FatPrePostIrp( IrpContext, Irp );
FatAddToWorkque( IrpContext, Irp );
//
// And return to our caller
//
return STATUS_PENDING;
Note that it ALWAYS returns STATUS_PENDING.
Thus, this isn’t a theoretical issue - it really CAN happen. It’s an issue specific to the way the native API function is written however.
Tony
OSR