A couple of weeks ago I was teaching our Developing file System Minifilters for Windows seminar here in Manchester, NH. A student asked a question about a behavior they were seeing when calling FltGetFileNameInformation after a rename operation on the network. Much to their surprise, the name returned was the old name for the file and not the new name. This is contrary to how the API works when called on a local file system, making it even more confusing. I hadn’t actually ever noticed this behavior, so I took off to track it down and see what was up…
Rename operations arrive at the minifilter as IRP_MJ_SET_INFORMATION for FileRenameInformation (or FileRenameInformationEx) requests. In PreRename, the file is not yet renamed and calling FltGetFileNameInformation returns the source file name information. If you want to know the destination name before the rename, you call FltGetDestinationFileNameInformation.
In PostRename, FltGetFileNameInformation should return you the new name of the renamed file. However, it appears there’s a “feature” in the network file systems that results in you being returned the old (source) name after a rename. There does not appear to be any way to avoid or fix this behavior, so if you call FltGetFileNameInformation in PostRename on the network you’re dealing with the wrong name.
You can “fix” this by instead caching the result of FltGetDestinationFileNameInformation in PreRename. The only problem with this is that renames are subject to name tunneling…
When you delete a file the Windows file systems will cache some of the file’s metadata in something called a “tunnel cache”. If you then quickly create or rename a file to the recently deleted name, the file system restores some of the previously deleted file’s attributes. Of primary interest to our story is that if you delete a file using its short name and then recreate the file using its short name, the original long name is magically restored (strange but true).
It’s a bit tricky to demonstrate the effect of the tunnel cache using standard Windows utilities, so I wrote a quick utility to demonstrate the tunnel cache behavior:
This brings us back to our rename problem. For example, a rename to “LONGNA~1.TXT” might actually result in a file being renamed to “LONG NAME.TXT”. The destination name you queried with FltGetDestinationFileNameInformation is still accurate in that case (i.e. the file does have the short name LONGNA~1.TXT), but it’s not been properly normalized. The way you fix this is on a local file system is by calling FltGetTunneledName in the PostRename callback, but that also returns you the incorrect old name on the network.
I’ve been trying to think of how to properly fix this and it would be pretty complicated to properly normalize the name yourself. Basically you would either need to open the destination file or containing directory and look to see if the name was tunneled. This isn’t too terrible, except things are always complicated on the network due to permissions. So, if you care about renames on the network, I’d stick with FltGetDestinationFileNameInformation in PreRename and know that the file component of the destination name might not be normalized.