Windows 文件链接
前叙
本文也可作为在 Unix 系统下软硬链接的一部分指导资料.
Windows Vista 以上, NTFS 文件系统支持三种类型的文件链接: 硬链接、交汇点(目录链接) 和 符号链接.
- 符号链接
- 符号链接是指向另一个文件系统对象的文件系统对象
- 链接目标为普通文件或目录
- 可以跨卷
- 与 UNIX 操作系统兼容
- 硬链接
- 多个路径引用同一卷中的单个文件
- 对硬链接文件所做的任何更改具有立即的传播性
- 交汇点
- 与硬链接相同, 引用的存储对象是单独的目录
- 可以跨卷
相关资料
这里主要关注 CMD 文档 与 fileIo 文档.
链接窗口
以下是 Windows 下一个经典的 mklink 提示:
文档与工具
与之对应的的 API 文档列表:
安装相应的辅助工具:
link-shell-extension 需要开启默认图标; Everything 需要在 工具-选项-索引-属性 添加 Reparse Tag
与 Reparse Target
并添加到显示列中(右键表头勾选). 软链接 与 fsutil 需要权限提升
符号链接
首先我们准备最大深度为 4 的文件树(各 txt 内容为文件名)
文件
创建链接
在深度 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
规则
将链接 LF10.txt 称为 A,链接 ALF10.txt 称为 B, 目标 F10.txt 称为 T
存在以下规则:
- A 与 T 的内容是一致的
- B 与 T 的内容是一致的
- 修改其中一个内容, 它们之间的内容也会同步
- 重命名 A, 规则 1,3 仍然成立
- 重命名 B, 规则 2,3 仍然成立
- 规则 1|3|4 的表现类似为 A 是对 T 的快捷方式
- 规则 2|3|5 的表现类似为 B 是对 T 的快捷方式
- 当 T 为可读写, 对 A 设置只读模式并不生效, 且该属性不同步到 B 或者 T, 对 T 的修改遵循规则 3
- 当 T 为可读写, 对 B 设置只读模式并不生效, 且该属性不同步到 A 或者 T, 对 T 的修改遵循规则 3
同时存在以下规则:
- 重命名 T, A 将无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
- 重命名 T, B 将无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
- 移动了 T, A 将无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
- 移动了 T, B 将无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
- 规则 1|2|3|4 中在程序开发中都称为对 T 的 移动 操作
- 在快捷方式创建之后, 当我们移动目标之后时, 快捷方式的文件目标属性会同步修改. 这与规则 1|2|3|4 的表现不同
- 移动了 A, A 将无法定位到 T 的内容, 尝试打开快捷属性, 资源管理器将抛出一个错误
- 移动了 B, B 仍可以定位到 T 的内容
- 当 T 为只读, 对 A 设置可写模式并不生效, 且该属性不同步到 B 或者 T
- 当 T 为只读, 对 B 设置可写模式并不生效, 且该属性不同步到 A 或者 T
元数据
在 Everything 中 搜索 parent:D:\wip regex:^(A){0,1}LF10.txt$
, 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.
名称 | 路径 | 大小 | Reparse Tag | Reparse Target |
---|---|---|---|---|
LF10.txt | D:\wip\ | 0 | 0xA000000C | DL00\FL10.txt |
ALF10.txt | D:\wip\ | 0 | 0xA000000C | D:\wip\DL00\FL10.txt |
或者使用 fsutil fsutil reparsePoint query .\LF10.txt
与 fsutil reparsePoint query .\ALF10.txt
根据 MSN 文档的结构定义(Reparse Point Tags, Reparse Point Data Structures), 可以分解出下边的结构示意图:
文件夹
该节与上一节内容一致, 因此只记录实操命令.
创建链接
以相对路径创建一个符号链接 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 Tag | Reparse Target |
---|---|---|---|---|
LDL10 | D:\wip\ | 0 | 0xA000000C | DL00\DL10 |
ALDL10 | D:\wip\ | 0 | 0xA000000C | D:\wip\DL00\DL10 |
或者使用 fsutil fsutil reparsePoint query LDL10
与 fsutil reparsePoint query ALDL10
目录链接
- 目录链接仅能在目录上创建
- 可以使用相对路径创建, 但创建成功之后表示为绝对路径
- 可以跨分区创建
创建链接
键入 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
规则
将链接 MDL20 称为 A,链接 AMDL20 称为 B, 目标 DL20 称为 T
存在以下规则:
- A 与 T 的内容是一致的
- B 与 T 的内容是一致的
- 修改其中一个内容, 它们之间的内容也会同步
- 移动了 A, A 将可以定位到 T 的内容
- 移动了 B, B 仍可以定位到 T 的内容
同时存在以下规则:
- 重命名 T, A 将无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
- 重命名 T, B 将无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
- 移动了 T, A 将无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
- 移动了 T, B 将无法定位到 T 的内容, 尝试打开目录, 资源管理器将抛出一个错误
- 规则 1|2|3|4 中在程序开发中都称为对 T 的 移动 操作
元数据
在 Everything 中 搜索 parent:D:\wip\DL00 regex:^(A){0,1}MDL20$
, 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.
名称 | 路径 | 大小 | Reparse Tag | Reparse Target |
---|---|---|---|---|
MDL20 | D:\wip\DL00\ | 0 | 0xA0000003 | D:\wip\DL00\DL10\DL20 |
AMDL20 | D:\wip\DL00\ | 0 | 0xA0000003 | D:\wip\DL00\DL10\DL20 |
或者使用 fsutil fsutil reparsePoint query MDL20
与 fsutil reparsePoint query AMDL20
硬链接
- 硬链接仅能在文件上创建
- 可以使用相对路径创建, 但创建成功之后表示为(相当于当前存储分区的根)绝对路径
- 不能跨分区创建
创建链接
键入 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
存在以下规则:
- A, B, C 指向文件系统中的同一个文件对象, 表现为指针
- A, B, C 的值修改都会立即同步(到引用位置列表的每一目标)
- A, B, C 的属性修改都会立即同步(到引用位置列表的每一目标)
- A, B, C 仅占用一份存储空间, 当所有链接被删除(引用为0)时, 存储才真正释放
- A, B, C 移动后仍然能正常工作
元数据
在 Everything 中 搜索 D:\wip\DL00 DL20.txt file:
, 可以较明显的看到元素据 Reparse Tag 与 Reparse Target.
名称 | 路径 | 大小 | Hard Link Count | Hard Link Filenames |
---|---|---|---|---|
DL20.txt | D:\wip\DL00\DL10\ | 1 KB | 3 | \wip\DL00\AHDL20.txt;\wip\DL00\HDL20.txt;\wip\DL00\DL10\DL20.txt |
HDL20.txt | D:\wip\DL00 | 1 KB | 3 | \wip\DL00\AHDL20.txt;\wip\DL00\HDL20.txt;\wip\DL00\DL10\DL20.txt |
AHDL20.txt | D:\wip\DL00 | 1 KB | 3 | \wip\DL00\AHDL20.txt;\wip\DL00\HDL20.txt;\wip\DL00\DL10\DL20.txt |
或者使用 fsutil fsutil.exe hardlink list .\HDL20.txt
附
Reparse Tag:
- IO_REPARSE_TAG_MOUNT_POINT: 0xA0000003
- IO_REPARSE_TAG_SYMLINK: 0xA000000C
注:
- 在遵循创建规则的情况下, 各种链接可嵌套
- 尽量使用绝对路径创建目录(符号)链接
- 遵循不移动符号链接目标的原则
- 符号链接在 SMB 共享时不生效(文件对象路径由客服端计算)
提问:
- 在一个符号链接上创建符号链接的结果
- 目录链接产生循环节点的后果