| Testing at the edge |
|
Hints and tips for exploring the corners of your Windows FSD or File System filter.
Several people have recently asked me about testing “into the corners of the file system”, and this article is an attempt to point out some of the darker corners that you may want to look into while testing file systems and file system drivers.
Often a change to a popular application or filter will suddenly cause grief on a hitherto stable filter; sometimes an API will suddenly become popular, and occasionally you will find someone pushing the edge of your design envelope. In any case it is always better to head this off in the lab.
So here is my top 10 list of things to think about when testing (and indeed when designing) an FSD or a file system filter. Not all of them will apply to you, but some of them will.
1. Test at the Native API as well at Win32.During early development I find it best to test at the native API – that way you get a one to one correspondence between operations that you send and IRPs that you see. I cannot speak too highly of Ladislav Zezula’s FileTest utility (available at OsrOnline and at Ladislav’s own site). This it exactly what you need to get going. As an added bonus the source is available so you can add calls for anything your product needs (for instance driver-specific ioctls and fsctls).
Once you have your driver more or less working you will want to write application level tests. Whether these tests are written at the Native API level (NtCreateFile, and so on) or the Win32 API level (CreateFile) will probably depend on whether the test is being written by a driver developer or not. If you write tests to the Win32 API you will be testing a subset of the calls which your filesystem or filter can see, but you will be testing using the paradigms used by a majority of the applications. If you write tests at the Native API level you will be able to test the entire breadth of the API (and it is broad - just consider, for instance, the different ways to rename a file). This can be particularly important when testing capabilities which are not widely available when you test but suddenly acquire a Win32 API. When testing against the Native API, you should be aware that the behaviours are not documented, and may not be what you expect, so always test against a reference implementation (usually NTFS) as well. No matter how you test, I urge that you test using both APIs with the balance between the two being driven by the needs of your specific product.
2. Streams, Dispositions and Delete on CloseIf your filter or file system handles streams (and most filters need to) you may need to make yourself aware of the ways in which the presence of a stream in a file name presented for create processing affects the operation of an FSD.
I am not going to discuss the precise semantics; they are not documented and hence may change. My experience is that although the behaviour is usually what you might expect after some thought about the problems, it is often not immediately intuitive. This is because the API doesn’t support streams as first class objects and so the precise semantics have had to be subject to best-guess approximations.
I recommend that you perform the nature study appropriate to your driver and then test as seems fit but here are few places to start thinking about.
It is my experience that a filter just has to adopt a pessimistic view in such situations (if a bad thing might happen, assume that it will). FSDs which seek to emulate the streams behaviour of NTFS have no other option than to test every single possible combination and emulate that. 3. IoCancelCreate & Stack based file objects
These are well described elsewhere (see for instance here). In general, filters should be very careful about using the file objects that they get given during create.
You should note that, contrary to what may have been stated elsewhere, it is still possible to be given stack based file objects in Vista.
4. Redirector behaviour
Because the API is the same, it is tempting to assume that filtering a redirector will be more or less the same as filtering a local file system. This topic is worthy of an article of its own, but for now here are some items to ponder:
Hint: the win16 program 'edit' is a great way to force the use of short names.
You will see this most often in Vista and/or when filtering MUP. These protocols include (but are not limited to) magic values being passed down in FsContext and FsContext2 during pre-created and out of band communication which your filter may never see. Client Side Caching and DFS are two components which have caused me problems, there are certainly others.
This is the most obvious issue. Redirectors work over unreliable media and so failures from the FSD should be considered as usual and not exceptional. Run your filter over RDR, pull out the Ethernet. What happens?
… And even for Windows there have been multiple versions of these subsystems. 5. Hard links
Hard links have been around since (at least) NT 3.54. Prior to Vista hard links tended to be the preserve of the people writing to the native API or using SFU.
Hard links became much more main-stream in Vista where they acquired a Win32 API (CreateHardLink) and have become a favourite mechanism for the Windows installer. Fortunately in Vista there are a few more tools to help the filter driver.
Considering hard links really boils down to two things:
In addition, NTFS will give the same Stream Context for a file regardless of the name used to open it but RDR won’t (as we saw above, a redirector cannot be aware of all the paths to a file).
In Vista a new QueryInformation (FileHardLinkInformation) call is declared by ntifs (although no documentation exists). This enumerates all the names for a file. In using it I have noted a couple of wrinkles you need to be aware of:
6. Explicit and implicit volume lockingIf your filter keeps handles open to the volume then you are probably already aware of the need to respond to FSCTL_LOCK_VOLUME (explicit locking). You may not be aware of the need to respond to an implicit lock – a volume open with restricted sharing.
The impact of this is best understood by inspecting the example code in the metadatatool examples shipped with the WDK. 7. Case sensitivitySince Windows 2000, case sensitivity in NTFS has been turned off in the registry and it has become a easy to ignore this issue.
However, SFU enables and enforces case sensitivity and it seems likely that NFS (more widely available in Vista) will have similar behaviour. If your file system or filter manipulates file names, then you should run some case sensitivity tests. IFSTest has a few case sensitive tests and is a good place to start.
In general , case sensitivity devolves to propagating the logical not of FO_OPENED_CASE_SENSITIVE into the RtlXXXUnicodeString functions.
8. The boot partition doesn’t have to be same as the system volume
If your product needs to know whether the volume you are working on is the system disk then you need to be aware that the boot partition (where the system initially boots from and indicated by DO_SYSTEM_BOOT_PARTITION) need not be the same as the system volume (where the '\Windows' directory is). The recommended way of locating the system disk is to open '\\SystemRoot', the returned file object will reference the system volume 9. Files which can require special handling
Depending on their function, filter drivers may need to handle certain files in particular ways. Often filters will decide that the best solution is to ignore creates to these files entirely. You should think about special handling for at least these files:
10. Interoperability testing with other filters
Interoperability testing can be open ended. This does not mean that you should not start it. I would recommend anyone to go to the regular IFS Plugfest events, which offer an unparalleled opportunity to test with a huge cross section of other filters. You may find that your first visit flushes several issues, but you will usually thereafter find that there are a few anti-patterns you should be avoiding. Of course, attendance at Plugfest is self selecting and so it is less likely that badly behaved filters (one which hook for instance) will be present. And finally…
Don’t forget to run both prefast and pclint over your code, and make sure that understand what it is saying to you.
If you have any comments on this article, please feel free to send me mail.
Equally, if you need help with planning the test of your driver, or with any other Windows file system project please feel free to contact Steading System Software. |


