如何在使用原始文件时删除 Windows NTFS 硬链接 (mklink /h)?

Mar*_*ica 11 windows ntfs file-management hardlink mklink

在 Windows NTFS 文件系统上,我有一个文件(比如orig.mp3)。我通过此路径orig.mp3以正在使用的方式打开此文件(例如,通过在 VLC 中播放它)。

然后我创建一个硬链接 ( cmd /c mklink /h link.mp3 orig.mp3)。这导致两个 NTFS 路径指向完全相同的文件。

最后,我再次尝试删除链接文件(del link.mp3,或在 Windows 资源管理器中删除)。

失败并显示错误:“该进程无法访问该文件,因为它正被另一个进程使用。”

为什么?更重要的是:我怎样才能避免这种情况(除了确保没有进程使用原始文件)?我是否可以告诉 Windows 进行“延迟删除”,以便在不再使用原始文件时自动删除链接文件?

小智 11

这是非常预期的行为,硬链接只是同一个文件的另一个名称。例如,如果您有文件 A.PDF,则创建指向同一个文件的硬链接 B.PDF,无论文件是以 A.PDF 还是 B.PDF 名称打开都没有关系 - 它仍然是同一个文件,所以如果这个文件只是被打开,你不能删除任何一个链接。

实际原因是名称作为属性存储在主文件表的文件记录中(在 NTFS 的情况下),并且由于文件已打开,因此您无法删除任何一个链接(您无法修改打开的文件)。

在这种情况下,没有什么像原始文件一样,因为两个名称都属于同一个(也是唯一一个)文件,并且两个名称相同。当链接计数达到零时,文件实际上被删除。

  • “为什么”是不完整的;如果删除硬链接是一种修改,那么添加也是一种修改,但是您可以添加硬链接来打开文件,而不是删除或重命名它们。我认为“为什么”只是决定在文件打开时不能重命名或删除硬链接;一个有意的设计决定。 (5认同)
  • 实际原因是,通常,无论其他硬链接打开,都不会调用 FILE_SHARE_DELETE。因此,在删除文件调用期间,删除权限会失败。请参阅以下注释:https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#file_share_delete (3认同)

sma*_*ipt 5

虽然上述答案对于何时和为何可以或不能删除硬链接并不完全错误,但可以通过查看此链接找到更准确的原因:

FILE_SHARE_DELETECreateFileA文档中的链接

如果未指定此标志,但已打开文件或设备进行删除访问,则该函数将失败。

当请求dwDesiredAccess 时,如果该文件(包括其硬链接对等体)有任何句柄打开,而这些句柄未经许可打开,则调用CreateFile将会失败。DELETEFILE_SHARE_DELETE

这就是尝试删除硬链接可能失败的一般原因 ( error code 5 access violation);要求必须关闭该文件的所有打开的硬链接对等方才能删除硬链接。

创建/删除可执行文件(可能是 nodejs/npm)的硬链接是一种常见模式,用于 nix-busybox 风格的 EXE 名称别名以共享单个 EXE 二进制文件。

对于硬链接的可执行文件,删除具有硬链接对等运行的可执行文件的硬链接将失败,因为 Windows 加载程序不会以权限打开可执行文件。当 service-exes 运行且您使用共享 exe 硬链接对等命名来创建这些 service-exes 时,这使得通过删除来管理安装删除/更新的硬链接变得非常烦人。作为一种模式,如果这是您的问题,请改用符号链接。尽管与硬链接不同,任何进程查看器(或类似的进程枚举 api)中的服务执行程序将使用符号链接目标名称而不是符号链接名称[叹气])。FILE_SHARE_DELETE

硬链接共享 NTFS 文件描述是正确的。

即,体积上的结构相同。另请注意,硬链接共享相同的 NTFSFILE_ID_INFO资源GetFileInformationByHandleEx - FileIdInfo (0x12)

但这并不是在对等链接打开时无法删除硬链接的原因。即使当对等链接打开时,您也可以创建更多到任何对等硬链接的硬链接,这一事实进一步证明了这一点;即使在任何对等点未经许可打开时您也无法删除它们FILE_SHARE_DELETE

如何在对等链接打开的情况下删除硬链接

  1. 使用可以向您显示硬链接对等点的工具。
  2. 使用一个工具,该工具将向您显示带有对硬链接或其对等方开放的句柄的进程。手动关闭/杀死它们。
  3. 使用文件观察器工具或使用文件观察器 api 在所有硬链接对等点关闭时删除硬链接(通过 #2)。
  4. 使用上面提到的 Win32MoveFileEx函数并MOVEFILE_DELAY_UNTIL_REBOOT等待/需要重新启动才能删除硬链接。

作为参考,我有一个使用这些类型的硬链接模式的工具集。它可以执行以上所有操作(它是通用 shell 和动态语言ess)。该工具集是EdgeShell,带有一个名为 的免安装二进制文件afm.exe

API 注意:执行与DeleteFiledwFlagsAndAttributes 相同的操作只需要FILE_FLAG_DELETE_ON_CLOSEand FILE_FLAG_OPEN_REPARSE_POINT(正确处理符号链接和连接重解析点而不是它们的目标)。

API 注意FindFirstFileNameW:您可以使用、FindNextFileNameW和枚举所有硬链接对等点FindClose。硬链接对等点只是 NTFS 文件节点的另一个 NTFS 目录节点条目名称引用(路径名)。由于它们共享 NTFS 卷的文件本身,并且目录节点信息的硬链接外部引用(反向指针)保存在该文件节点中,因此硬链接必须位于同一 NTFS 卷上。

注意复制到硬链接文件和重新分析点的 NTFS 文件共享

如果您使用大多数命令行或编辑器工具将文件复制到硬链接上,它通常会删除/破坏硬链接并创建该文件的新独立副本,这可能非常不直观。

如果您的目标是实际替换硬链接文件的内容,以便硬链接及其所有对等体共享复制的数据,那么您通常需要一个能够识别该操作的硬链接的工具(带/不标记选项)。

如果您没有此类工具,最好“打开”有问题的硬链接文件并就地“写入”所需的新内容(不要使用通用文件复制工具)。请注意,许多 IDE 编辑器(VsCode、Visual Studio)将使用 std c-lib api 来实际删除然后替换文件(破坏硬链接)。 这可能会变得非常混乱。

Windows 世界一直拥有强大的 NTFS 功能,但长期以来缺乏处理硬链接、符号链接(和连接)的 nix 知识和工具。

文件共享和链接:事实上,JUNCTIONS 非常棒。特别是当您了解在 NTFS 卷的网络文件共享中处理 JUNCTIONS 和 SYMLINK 重分析点之间的真正区别时。

即,SYMLINK 在 CLIENT 计算机上解析,但 JUNCTION 在 SERVER 计算机上解析。

这意味着带有符号链接 C:\something 的 NTFS 卷将在客户端计算机的 C 驱动器上查找(因为该链接在客户端上解析),但 JUNCTION 将在服务器的 C 驱动器上查找(因为链接在服务器上解析),从而解析服务器上的路径,并且不会向客户端公开联结重新解析。

要配置 NTFS 共享行为,请参阅

fsutil 行为设置 SymlinkEvaluation

symlinkevaluation <symboliclinktype>控制可以在计算机上创建的符号链接的类型。有效的选择是:

  1. 本地到本地符号链接,L2L:{0|1}
  2. 本地到远程符号链接,L2R:{1|0}
  3. 远程到本地符号链接,R2L:{1|0}
  4. 远程到远程符号链接,R2R:{1|0}