问题导致的需求
最近的工作上有个升级COM组件的需求,但是我们这个COM组件每次注册的时候,其对应的dll路径及文件名是固定不变的;
这就遇到了一个状况,如果该dll正在被加载使用中,如何去替换它呢?(当然,如果注册的时候允许dll变更文件名就没有这个困扰)
正在被使用中的文件进行删除操作是会失败的,所以不可能通过拷贝覆盖的方法来做,当时的第一念头就是通过symbolic link来完成这个事情。
只要后续我们这个注册表中指向的固定路径是一个symbolic link,那么一旦有升级的需求,只需要拷贝升级dll到同个目录下(当然要进行改名以避免同名dll使用中导致无法覆盖的情况),删除原symbolic link,创建过一个新的同名symbolic link,但是其指向升级dll即可。
这个方案在vista及以上的系统是没有问题的,但是由于xp不支持symbolic link,所以上述方案最终还是没有实施,而是换过了另外一套方案,跟本文的主题无关,这里就不详述了,有空会再写一篇文章来总结这个事情。
下面还是回到正题上来,探讨Windows下的几种链接形式,以下的文字大部分引用了这篇文章《Windows硬链接 软链接 符号链接 快捷方式》
shortcut(快捷方式)
- 以.lnk文件方式存在,适用于Explorer等应用程序(其本质上也是一个文件,所以占用空间,只是存储的是一些跳转信息,只为Explore等程序能识别使用)。
- 非NTFS内置机制,从Win95开始得到支持。FAT32支持。
- 同时适用于文件、目录。
- 只能使用绝对路径。
- 可以跨盘符,可以跨主机,可以使用UNC路径、网络驱动器。
- 删除shortcut,不影响target。
hard link(硬链接)
- 有点类似文件指针的概念,只有真正一份数据存储在硬盘上,只有当所有的硬链接都被删除时,才真正删除这个文件
- NTFS内置机制,从Windows NT 4开始得到支持。FAT32不支持。
- 只适用于文件。
- 只能使用绝对路径。
- hard link与target file必须位于同一volume,可以简单理解成不能跨盘符。
- 在Explorer中删除hard link,不影响target file。
- 删除target file,不影响hard link。事实上由于hard link的语义,此时剩下的hard link就是原始数据的唯一访问点。
- 相关Win32 API:
CreateHardLink()
CreateHardLinkTransacted()
- 创建:
mklink /H "hard link name" "target file"
fsutil.exe hardlink create "hard link name" "target file"
- 查看:
fsutil.exe hardlink list "hard link name"
fsutil.exe hardlink list "target file"
junction point/soft link/reparse point
- junction point也叫soft link,这是微软官方文档里说的:
Hard Links and Junctions
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365006
- junction point的底层机制是NTFS的reparse point:
Reparse Points
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365503
Junction v1.06
http://www.sysinternals.com
http://technet.microsoft.com/en-us/sysinternals/default.aspx
https://technet.microsoft.com/en-us/sysinternals/bb896768
How to create and manipulate NTFS junction points
https://support.microsoft.com/en-us/kb/205524
- NTFS内置机制,从Windows 2000/XP开始得到支持。
- 只适用于目录。Vista的"C:\Documents and Settings"是指向"C:\Users"的junction point,这样一些使用了硬编码"C:\Documents and Settings"的老程序可以在Vista上正常工作。
- 只能使用绝对路径。即使创建junction point时使用了相对路径,保存到NTFS中时将隐式转换成绝对路径。
- junction point必须与target directory位于同一local computer,可以简单理解成不能跨主机。不能使用UNC路径;假设Z是通过网络映射生成的盘符,同样不适用于Z。
- 在local computer范围内,可以跨盘符。
- 在Explorer中删除junction point,有两种情况。对于Windows 2000/XP/2003,会同步删除target directory,这真是一个奇葩的行为。注意,我们强调,在Explorer中删除,高版本的Total Commander没有这个奇葩行为。对于Vista及之后版本,不影响target directory,这才是人类所能理解的行为。
- 删除target directory,junction point仍将存在,但失效了,变得不可用。这个很好理解,因为此时junction point指向不存在的目录。
diskmgmt.msc
右键选中某volume
更改驱动器号和路径
添加
装入以下空白NTFS文件夹中
这个功能用的就是junction point机制,还可以用mountvol.exe完成操作。
- 创建:
mklink /J "junction point name" "target directory" // 生成的Reparse Data相比junction.exe要多
linkd.exe "junction point name" "target directory" // Windows Resource Kits
- 查看:
dir /A:L /S "path"
fsutil.exe reparsepoint query "junction point name" // 有Reparse Data的16进制转储
linkd.exe "junction point name" // 不能查看junction.exe生成的"junction point"
- 删除:
fsutil.exe reparsepoint delete "junction point name" // 不建议使用
linkd.exe "junction point name" /D // 可以删除junction.exe生成的"junction point"
它这个行为不是我们期望的效果,比如"target directory"下有普通文件,
上述命令会删除"junction point"下的普通文件,但不会删除"junction point",
同时"target directory"下的普通文件仍然存在。这个效果我不能理解。
在Explorer中操作无法达到这种效果。
- sysinternals的junction.exe:
junction.exe "junction point name" "target directory" // 创建
junction.exe "junction point name" // 查看
junction.exe -q -s "path" // 递归查看
junction.exe -d "junction point name" // 删除
我猜junction.exe提供-d参数,就是因为Windows 2000/XP/2003的Explorer奇葩行为,
这个-d不影响target directory。
示例:
"dir /A:L /S c:\
2009/07/14 13:08 "JUNCTION" Documents and Settings [C:\Users]
"junction.exe "C:\Documents and Settings"
C:\Documents and Settings: JUNCTION
Print Name : C:\Users
Substitute Name: C:\Users
"junction.exe -q -s c:\
\\?\c:\\Documents and Settings: JUNCTION
Print Name : C:\Users
Substitute Name: C:\Users
symbolic link
Symbolic Links
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365680
- NTFS内置机制,从Vista开始得到支持。
- 同时适用于文件、目录。这是一种超级shortcut。
- 可以使用相对、绝对路径。假设创建symbolic link时使用了相对路径,保存到NTFS中的就是相对路径,不会隐式转换成绝对路径。
- 可以跨盘符,可以跨主机,可以使用UNC路径、网络驱动器。
- 在Explorer中删除symbolic link,不影响target。
- 删除target,symbolic link仍将存在,但失效了,变得不可用。
- 相关Win32 API:
CreateSymbolicLink()
CreateSymbolicLinkTransacted()
- 创建:
mklink "file symbolic link name" "target file"
mklink /D "directory symbolic link name" "target directory"
注意不指定/D时创建file symbolic link,指定/D创建directory symbolic link。