为什么 FindFirstFile / FindNextFile 有时会看到网络文件夹中的文件,但 CopyFile 却看不到?

Why do FindFirstFile / FindNextFile sometimes see a file on a network folder, but CopyFile does not?

我有一个功能,应该通过将所有文件从源文件夹复制到目标文件夹来创建源文件夹的备份。该函数使用由 FindFirstFile / FindNextFile 驱动的 while 循环,然后为 Find... 函数找到的每个文件调用 CopyFile

现在当源文件夹是一个SMB网络路径时(不管我使用的是映射驱动器还是UNC路径),有时会发生FindNextFile "sees"一个文件,但是CopyFile 拒绝复制文件。错误码为2,即ERROR_FILE_NOT_FOUND.

我觉得这难以置信,所以我在调用 CopyFile 之前向备份函数添加了对 _access 的调用,以检查文件是否存在。结果与 CopyFile 相同,即 _access 报告文件不存在(return 代码 -1 且 errno 为 2,即 ENOENT ).

所以我的主要问题是:网络文件夹中的 FindFirstFile / FindNextFile "sees" 文件怎么可能既不是 CopyFile 也不是 _access可以看到吗?

附加信息/诊断:

不幸的是,我对此进行的研究没有找到任何有用的信息,所以我只能推测。如果 FindFirstFile / FindNextFile / CopyFile 确实不能很好地协同工作,你知道另一组 find/copy API 函数更可靠吗?

这可能是因为 windows 上的 SMB 2.0 维护了一个缓存,该缓存仅每 10 秒刷新一次。

请参阅 this blog archive 文章了解更多信息和程序化解决方法。

File.Exists /_access / GetFileAttributes / FindFirstFile,FindNextFile / _stat behavior over SMB 2.0

What is really happening?

This is because of the local caching included on the client side with SMB 2.0. When the SMB 2.0 session has been created, the local cache will be available on the client side, which will be refreshed after every 10 seconds by default. Any further request to the file exists will be checked against this local cache rather than going to the server share. So, if a local cache is built on client, and on server share a new file is created, local cache has not been invalidated and not in sync with server share, any further request for checking the new file existence will fail.

This is root cause, but by design. If the local cache is updated and in sync with server share, request will be successful.

resolution/work左右,链接文章提到:

How do I control the local cache lifetime?

You can create registry keys below to control the cache lifetime.
Under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters:

  • FileInfoCacheLifetime
  • FileNotFoundCacheLifetime
  • DirectoryCacheLifetime

They are all REG_DWORD type in seconds.

Programmatic workaround?

Register for directory or file change notifications using Win32 API.
Use FindFirstChangeNotification Function (Windows) API to register for changes.