Although the FileAccessInformation, FileAlignmentInformation, and FileModeInformation information types can also be passed as a parameter to ZwQueryInformationFile, this information is file-system-independent. Thus ZwQueryInformationFile supplies this information directly, without sending an IRP_MJ_QUERY_INFORMATION request to the file system.
- the access rights for each handle are managed by the IO manager internally
and they are not visible on the FILE_OBJECT or even stored in the file system.
So even if the IO manager were to send an IRP, the file system itself wouldn't
be able to answer the request because it just doesn't have that information. I
should mentioned that this isn't necessarily true for remote file systems since
the remote file system must perform access checks for the requests it receives
over the wire anyway.
- this alignment is not something required by the file system anyway. This is related to the storage
device on top of which the file system is mounted and so the IO manager could
get it by querying the storage device. However, that's not really necessary
since each DEVICE_OBJECT has an AlignmentRequirement member (again, this might
not be true for remote file systems).
- this information comes from the FILE_OBJECT and it's pretty transparent how it maps
to the various FILE_OBJECT flags.
So as we can see FastFat doesn't even attempt to return the data for those information classes mentioned in the documentation. So how are they populated ? My first guess was that the IO manager populates them after the request completes and before returning the buffer to the caller. But when I tried to validate my assumption by setting a write breakpoint on the location in the buffer where the FILE_ACCESS_INFORMATION structure is the breakpoint never got hit in the path I expected it to.. After some more investigation I realized that by the time my filter got the request, the FILE_ACCESS_INFORMATION was already populated:case FileAllInformation: // // For the all information class we'll typecast a local // pointer to the output buffer and then call the // individual routines to fill in the buffer. // AllInfo = Buffer; Length -= (sizeof(FILE_ACCESS_INFORMATION) + sizeof(FILE_MODE_INFORMATION) + sizeof(FILE_ALIGNMENT_INFORMATION)); FatQueryBasicInfo( IrpContext, Fcb, FileObject, &AllInfo->BasicInformation, &Length ); FatQueryStandardInfo( IrpContext, Fcb, &AllInfo->StandardInformation, &Length ); FatQueryInternalInfo( IrpContext, Fcb, &AllInfo->InternalInformation, &Length ); FatQueryEaInfo( IrpContext, Fcb, &AllInfo->EaInformation, &Length ); FatQueryPositionInfo( IrpContext, FileObject, &AllInfo->PositionInformation, &Length ); FatQueryNameInfo( IrpContext, Fcb, Ccb, &AllInfo->NameInformation, &Length ); break;
So the way NtQueryInformationFile works for FileAllInformation is by populating the buffer with the information it has access to before sending it to the file system and then the file system fills in the rest. With this in mind there are a couple of things that filters must be careful about:1: kd> kn # ChildEBP RetAddr 00 a625eb6c 96016aeb myfilter!PreQueryInformation+0x29c 01 a625ebd8 960199f0 fltmgr!FltpPerformPreCallbacks+0x34d 02 a625ebf0 96019f01 fltmgr!FltpPassThroughInternal+0x40 03 a625ec14 9601a3ba fltmgr!FltpPassThrough+0x203 04 a625ec44 828884bc fltmgr!FltpDispatch+0xb4 05 a625ec5c 82aa8f24 nt!IofCallDriver+0x63 06 a625ed18 8288f44a nt!NtQueryInformationFile+0x779 1: kd> ?? ((PFILE_ALL_INFORMATION)Data->Iopb->Parameters.QueryFileInformation.InfoBuffer)->AccessInformation struct _FILE_ACCESS_INFORMATION +0x000 AccessFlags : 0x120089
processing a FileAllInformation request the filter must be careful not to
overwrite the information that was already written by the IO manager. So don't
call RtlZeroMemory() for that buffer or reuse it for some other purpose. Also,
if completing an FileAllInformation query from assembling bits from some other
sources (other queries into an underlying file system or some such) the filter
must be careful about how it copies the data into the user's buffer. I've see
cases where in response to a FileAllInformation request the filter allocated
its own buffer, sent its request using FltQueryInformationFile() and then
copied the resulting buffer over the user's buffer and that is broken. This is
is not meant to be identical to ZwQueryInformationFile(). It is simply a
wrapper over allocating an IRP and sending the request to the file system, so
some (all ?) of the requests that would be completed by the IO manager without
sending an IRP will just fail for FltQueryInformationFile().
that implement more of the file system functionality need to behave more like a
file system so for example a filter that owns its own FILE_OBJECTs must make
sure to keep the CurrentByteOffset updated since the FilePositionInformation request
might be completed above them by the IO manager or some other filter that will
simply look in the FILE_OBJECT.