Windows 文件链接

前叙

本文也可作为在 Unix 系统下软硬链接的一部分指导资料.

Windows Vista 以上, NTFS 文件系统支持三种类型的文件链接: 硬链接、交汇点(目录链接) 和 符号链接.

  1. 符号链接
    1. 符号链接是指向另一个文件系统对象的文件系统对象
    2. 链接目标为普通文件或目录
    3. 可以跨卷
    4. UNIX 操作系统兼容
  2. 硬链接
    1. 多个路径引用同一卷中的单个文件
    2. 对硬链接文件所做的任何更改具有立即的传播性
  3. 交汇点
    1. 与硬链接相同, 引用的存储对象是单独的目录
    2. 可以跨卷

相关资料

这里主要关注 CMD 文档 与 fileIo 文档.

链接窗口

以下是 Windows 下一个经典的 mklink 提示:

image

文档与工具

与之对应的的 API 文档列表:

安装相应的辅助工具:

link-shell-extension 需要开启默认图标; Everything 需要在 工具-选项-索引-属性 添加 Reparse TagReparse Target 并添加到显示列中(右键表头勾选). 软链接 与 fsutil 需要权限提升


符号链接

首先我们准备最大深度为 4 的文件树(各 txt 内容为文件名)

image


文件

创建链接

在深度 0 的 wip 文件夹中

  • 相对路径创建一个符号链接 LF10.txt, 链接文件夹 DL00 中的文件 F10.txt (深度1): mklink LF10.txt DL00\FL10.txt
  • 绝对路径创建一个符号链接 ALF10.txt, 链接文件夹 DL00 中的文件 F10.txt (深度1): mklink ALF10.txt D:\wip\DL00\FL10.txt

Windows-文件链接-软0

规则

将链接 LF10.txt 称为 A,链接 ALF10.txt 称为 B, 目标 F10.txt 称为 T

存在以下规则:

  1. AT 的内容是一致的
  2. BT 的内容是一致的
  3. 修改其中一个内容, 它们之间的内容也会同步
  4. 重命名 A, 规则 1,3 仍然成立
  5. 重命名 B, 规则 2,3 仍然成立
  6. 规则 1|3|4 的表现类似为 A 是对 T 的快捷方式
  7. 规则 2|3|5 的表现类似为 B 是对 T 的快捷方式
  8. T 为可读写, 对 A 设置只读模式并不生效, 且该属性不同步到 B 或者 T, 对 T 的修改遵循规则 3
  9. T 为可读写, 对 B 设置只读模式并不生效, 且该属性不同步到 A 或者 T, 对 T 的修改遵循规则 3

同时存在以下规则:

  1. 重命名 T, A无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
  2. 重命名 T, B无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
  3. 移动了 T, A无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
  4. 移动了 T, B无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
  5. 规则 1|2|3|4 中在程序开发中都称为对 T 的 移动 操作
  6. 在快捷方式创建之后, 当我们移动目标之后时, 快捷方式的文件目标属性会同步修改. 这与规则 1|2|3|4 的表现不同
  7. 移动了 A, A无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
  8. 移动了 B, B可以定位到 T 的内容
  9. T 为只读, 对 A 设置可写模式并不生效, 且该属性不同步到 B 或者 T
  10. T 为只读, 对 B 设置可写模式并不生效, 且该属性不同步到 A 或者 T

元数据

Everything 中 搜索 parent:D:\wip regex:^(A){0,1}LF10.txt$, 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.

名称路径大小Reparse TagReparse Target
LF10.txtD:\wip\00xA000000CDL00\FL10.txt
ALF10.txtD:\wip\00xA000000CD:\wip\DL00\FL10.txt

或者使用 fsutil fsutil reparsePoint query .\LF10.txt fsutil reparsePoint query .\ALF10.txt image

根据 MSN 文档的结构定义(Reparse Point Tags, Reparse Point Data Structures), 可以分解出下边的结构示意图:

image

image


文件夹

该节与上一节内容一致, 因此只记录实操命令.

创建链接

相对路径创建一个符号链接 LDL10, 链接文件夹 DL00 中的文件夹 DL10 (深度1): mklink /d LDL10 DL00\DL10.

绝对路径创建一个符号链接 ALDL10, 链接文件夹 DL00 中的文件夹 DL10 (深度1): mklink /d ALDL10 D:\wip\DL00\DL10.

规则

元数据

Everything 中 搜索 parent:D:\wip dir: regex:^(A){0,1}LDL10$ , 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.

名称路径大小Reparse TagReparse Target
LDL10D:\wip\00xA000000CDL00\DL10
ALDL10D:\wip\00xA000000CD:\wip\DL00\DL10

或者使用 fsutil fsutil reparsePoint query LDL10 fsutil reparsePoint query ALDL10 image


目录链接

  1. 目录链接仅能目录上创建
  2. 可以使用相对路径创建, 但创建成功之后表示为绝对路径
  3. 可以跨分区创建

创建链接

键入 cd /d D:\wip\DL00 切换工作目录

  • 相对路径创建一个目录链接 MDL20, 链接文件夹 DL00 中的目录 DL20 (深度2): mklink /j MDL20 DL10\DL20
  • 绝对路径创建一个目录链接 AMDL20, 链接文件夹 DL00 中的目录 DL20 (深度2): mklink /j AMDL20 D:\wip\DL00\DL10\DL20

image

规则

将链接 MDL20 称为 A,链接 AMDL20 称为 B, 目标 DL20 称为 T

存在以下规则:

  1. AT 的内容是一致的
  2. BT 的内容是一致的
  3. 修改其中一个内容, 它们之间的内容也会同步
  4. 移动了 A, A可以定位到 T 的内容
  5. 移动了 B, B可以定位到 T 的内容

同时存在以下规则:

  1. 重命名 T, A无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
  2. 重命名 T, B无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
  3. 移动了 T, A无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
  4. 移动了 T, B无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
  5. 规则 1|2|3|4 中在程序开发中都称为对 T 的 移动 操作

元数据

Everything 中 搜索 parent:D:\wip\DL00 regex:^(A){0,1}MDL20$, 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.

名称路径大小Reparse TagReparse Target
MDL20D:\wip\DL00\00xA0000003D:\wip\DL00\DL10\DL20
AMDL20D:\wip\DL00\00xA0000003D:\wip\DL00\DL10\DL20

或者使用 fsutil fsutil reparsePoint query MDL20fsutil reparsePoint query AMDL20

image


硬链接

  1. 硬链接仅能文件上创建
  2. 可以使用相对路径创建, 但创建成功之后表示为(相当于当前存储分区的根)绝对路径
  3. 不能跨分区创建

创建链接

键入 cd /d D:\wip\DL00 切换工作目录

  • 相对路径创建一个硬链接 HDL20.txt, 链接文件夹 DL00 中的文件 DL20.txt (深度2): mklink /h HDL20.txt DL10\DL20.txt
  • 绝对路径创建一个硬链接 AHDL20.txt, 链接文件夹 DL00 中的文件 DL20.txt (深度2): mklink /h AHDL20.txt D:\wip\DL00\DL10\DL20.txt

注:

  • 硬链接没有快捷属性页
  • 硬链接的所每个连接属性页的 引用基数引用位置列表 都是一致

规则

将链接 HDL20.txt 称为 A,链接 AHDL20.txt 称为 B, 目标 DL20.txt 称为 C

存在以下规则:

  1. A, B, C 指向文件系统中的同一个文件对象, 表现为指针
  2. A, B, C 的值修改都会立即同步(到引用位置列表的每一目标)
  3. A, B, C 的属性修改都会立即同步(到引用位置列表的每一目标)
  4. A, B, C 仅占用一份存储空间, 当所有链接被删除(引用为0)时, 存储才真正释放
  5. A, B, C 移动后仍然能正常工作

元数据

Everything 中 搜索 D:\wip\DL00 DL20.txt file: , 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.

名称路径大小Hard Link CountHard Link Filenames
DL20.txtD:\wip\DL00\DL10\1 KB3\wip\DL00\AHDL20.txt;\wip\DL00\HDL20.txt;\wip\DL00\DL10\DL20.txt
HDL20.txtD:\wip\DL001 KB3\wip\DL00\AHDL20.txt;\wip\DL00\HDL20.txt;\wip\DL00\DL10\DL20.txt
AHDL20.txtD:\wip\DL001 KB3\wip\DL00\AHDL20.txt;\wip\DL00\HDL20.txt;\wip\DL00\DL10\DL20.txt

或者使用 fsutil fsutil.exe hardlink list .\HDL20.txt image


Reparse Tag:

  1. IO_REPARSE_TAG_MOUNT_POINT: 0xA0000003
  2. IO_REPARSE_TAG_SYMLINK: 0xA000000C

注:

  1. 在遵循创建规则的情况下, 各种链接可嵌套
  2. 尽量使用绝对路径创建目录(符号)链接
  3. 遵循不移动符号链接目标的原则
  4. 符号链接在 SMB 共享时不生效(文件对象路径由客服端计算)

提问:

  1. 在一个符号链接上创建符号链接的结果
  2. 目录链接产生循环节点的后果