views:

251

answers:

3

My question is a slight variation on the question What is the best way to test whether a file exists on Windows?, with some specific caveats. Specifically, the data is located on a mapped drive, and the SMB 2.0 protocol is used. (By definition, this requires that the drive be mapped from a Vista machine to either a Vista or Server 2008 machine.)

The problem with the answers posted in reply to the above question is that SMB 2.0 caches a bunch of metadata, including filenames in a given directory. As a result, if you are testing for the existence of a file that was just created, then functions _access, access, GetFileAttributes, and CreateFile (and perhaps others) will all use cached information to answer the question "does this file exist?". If the file was very recently created by another user, the cache indicates that the file is not present, despite the fact that it does indeed exist. I've set up test environments to test this, and I can confirm that no SMB2 traffic is generated by the client for several seconds [presumably the cache expires every 5 seconds or so].

Has anyone else seen this? (If so, did you find a workaround other than adding a delay/retry?) Does anyone know of any API similar to the above that can check for file existence without using the SMB cache? Or, better yet, does anyone know of a Windows API that will simply dump the cached SMB metadata?

A: 

Just open it.

Randy Proctor
If only it were that simple. If you see my reply to John Zwinck's question above, the net effect of this caching is that the client will not attempt to open a file it doesn't think exists. CreateFile always works when dwCreationDisposition is CREATE_ALWAYS, but can fail if any other value is used.
Jedidiah Thomet
A: 

Call open(path, O_CREAT | O_EXCL, mode) and check the result. This results in an error if the file already exists. Surely this will write-thru the SMB cache and give correct results, otherwise it would be very unreliable. So if the call succeeds then file file didn't exists but it does now, so you may need to delete it (depends on app logic). If the call fails the file already existed.

dwc
A: 

While not a programmatic solution, I found an effective workaround (with the help of Microsoft support). I wanted to post the workaround here in case anyone else is as frustrated by this as I have been. Because this behavior is a "feature" of SMB2, Microsoft has provided the following registry entries to override the default metadata cache lifetime:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters\FileInfoCacheLifetime 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters\FileNotFoundCacheLifetime 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters\DirectoryCacheLifetime

Each of these are DWORD values, which can be set according to your needs. (Setting these to 0 on the SMB2 client was effective in resolving my issue.)

Jedidiah Thomet