0

我正在处理以下代码:

  • 枚举源目录和目标目录并生成 { src, dst} 对

  • ...每一对都被发送到一个工作线程池

  • ...执行工作,例如“复制srcdst

(所有这些都被简化了很多)。

问题:

创建文件时,它还会获得一个短名称,该短名称可以与源目录中的另一个文件相同(名称冲突),这会导致各种效果(取决于操作顺序)。例如,复制两个文件my fileMYFILE~1可以在目标中生成 2 个或 1 个文件(取决于您的运气),可能包含损坏的内容(在后一种情况下)。

问题:

如何避免此类碰撞产生的问题?有一个函数可以创建/打开忽略短名称的文件会很好......

笔记:

  • 不能假设任何关于短名称的生成方式。不同的系统采用不同的方案(见这个

  • 即使您以顺序方式(一个接一个)运行这些作业——它们也需要按顺序执行,这取决于短名称生成逻辑(这是未知的)。另外,这意味着在运行任何作业之前在内存中加载和排序/等整个目录

  • 源和目标都可能非常大(可能是数百万个文件),(如果可能的话)我想避免将整个目录加载到内存中或多次枚举它

  • 无法关闭目标卷中的短名称生成并将其作为要求不是一种选择(另外,将其关闭也不会删除现有的短名称)

  • 应用程序仅限于 Win32 API 和 NT API

编辑:在我看来,在一般情况下,即使所有事情都发生在一个线程上,您也无法做到这一点——仅仅是因为无论您选择什么顺序,都会有一个短名称生成方案和一组保证产生的文件名处理过程中的碰撞。

如果这是正确的 - 系统实用程序如何复制文件?在复制完成后,他们是否假设一些关于短名称的内容或执行“验证和修复差异”?

4

1 回答 1

0

问题基本上归结为以下几点:dst永远不应该通过shortname.

例如(如果是NT API),可以这样实现:

  • 打开(NtCreateFile(),不截断)时dst用作FILE_OPEN_IFCreateDisposition

  • 成功时检查IoStatusBlock::Information文件是否已创建 ( FILE_CREATED)

    • 如果是 - 不需要做任何事情(不可能通过短名称创建文件)

    • 如果没有 - 通过检查当前文件名NtQueryInformationFile(FileNameInformation)

      • 如果名称与提供给的名称不同(区分大小写!)NtCreateFile()-- 错误

并行进程可以在您打开文件后立即重命名文件,但我会将其视为错误。

错误可能导致几次重试,然后是硬故障(需要人工注意)。由于冲突文件的名称由NtQueryInformationFile().

PS 可以采取额外的步骤来防止/减少碰撞。例如,如果短名称生成逻辑是已知的——dst对象可以按特定顺序处理。

于 2020-10-07T20:55:57.237 回答