I based Filemon on a type of device driver called a filter driver, which I described in a previous column (see "Inside On-Access Virus Scanners," September 1997). NT describes file I/O with discrete command packets called I/O request packets (IRPs). NT's file-related services, which have names such as NtReadFile and NtCreateFile, create IRPs. When an application performs a file access, the application indirectly invokes one or more file-related services, and the I/O Manager delivers the resulting IRPs to the file system driver responsible for managing the target file. The I/O Manager locates the file system driver through one of the driver's device objects that serves as a logical representation of the file on which the driver resides.
NT's I/O model lets filter drivers create device objects that attach to other device objects. The I/O Manager can route IRPs (which the I/O Manager would otherwise send to the device driver associated with the underlying object) to the filter driver that owns the object that has attached to the target device object. Thus, the I/O Manager hands to the filter driver IRPs aimed at the object the driver is filtering. When you direct Filemon to watch a certain drive, Filemon creates a filter device object and attaches it to the drive's file system device object. From that point, Filemon receives and inspects all the IRPs directed at the drive, records information about the IRPs in memory buffers, then passes the IRPs on to the file system driver. For each IRP it sees, Filemon registers with the I/O Manager a request to see the IRP again after the file system driver has finished servicing it. Filemon can then record what time an operation completes and the operation's status. The Filemon user interface (UI) periodically requests the latest batch of activity buffers from the driver and displays the records the buffers contain in the Filemon output window. Figure 1 shows the relationships between applications, device objects, IRPs, Filemon's filter driver, and file system drivers.
Because Filemon intercepts IRPs, you see commands such as IRP_MJ_READ and IRP_MJ_CREATE in Filemon's output window, rather than more familiar commands, such as Read and Open. In Filemon's output windows, you'll also see non-IRP command names such as FASTIO_READ and FASTIO_QUERY_BASIC_INFORMATION. These commands represent the Fast I/O shortcut path that NT uses to speak with file system drivers. This path is a shortcut because it bypasses the creation of IRPs, and with the path, the I/O Manager directly invokes functions within file system drivers to carry out requests. You can see both IRP-related and Fast I/O commands because file system drivers can service Fast I/O requests only if the accessed file data is in the file system cache and several other conditions hold. If a file system driver returns a Fast I/O command status of FALSE, the I/O Manager falls back on the IRP-based request path.
A pathname you'll frequently see is DASD. This pathname stands for Direct Access Storage Device and is the name Microsoft uses to describe I/O that bypasses the file system data structures. This pathname occurs so frequently because Filemon shows the requests that file systems make to update their on-disk data structures, such as FAT's File Allocation Table or NTFS's Master File Table (MFT). Because file systems aim these requests at files with no explicit name, Filemon uses DASD.
Describing the meaning of every command type and status code is outside the scope of this article, but the important command types and status codes are self-explanatory. Full source code to Filemon is on the Systems Internals Web site.