1.9 shortcut/hard link/junction point/symbolic link简介
https://scz.617.cn/windows/201510151343.txt
A: scz 2015-10-15 13:43
Windows支持4种"链接"机制,分别是shortcut、hard link、junction point、 symbolic link。本文针对这4种机制进行简要介绍,可作为速查手册存在。
先吐个槽,天朝很多与本问题相关的技术文章,在术语层面相当混乱,作者的一知半 解以及不使用规范术语,给本就容易混淆的概念带来更大的误导。
1) shortcut/快捷方式
以.lnk文件方式存在,适用于Explorer等应用程序。
非NTFS内置机制,从Win95开始得到支持。FAT32支持。
同时适用于文件、目录。
只能使用绝对路径。
可以跨盘符,可以跨主机,可以使用UNC路径、网络驱动器。
删除shortcut,不影响target。
删除target,shortcut仍将存在,但失效了,变得不可用。
2) (file) hard link
假设本文读者具有*nix基础,此处不做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
查看:
fsutil.exe hardlink list
二者效果一样,hard link的语义本就如此。
删除:
del
LTSB Win10有安全限制,禁止创建下述"(file) hard link":
$ mklink /H C:\temp\regedit_hlink.exe C:\Windows\regedit.exe Access is denied.
3) (directory) 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
查看:
dir /A:L /S
删除:
fsutil.exe reparsepoint delete
它这个行为不是我们期望的效果,比如
linkd.exe
sysinternals的junction.exe:
junction.exe
我猜junction.exe提供-d参数,就是因为Windows 2000/XP/2003的Explorer奇葩行为, 这个-d不影响target directory。
示例:
dir /A:L /S c:\ 2009/07/14 13:08
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
4) symbolic link
Symbolic Links https://msdn.microsoft.com/en-us/library/windows/desktop/aa365680
symbolic link不是soft link,不要跟着SB瞎起哄。
NTFS内置机制,从Vista开始得到支持。
同时适用于文件、目录。这是一种超级shortcut。
可以使用相对、绝对路径。假设创建symbolic link时使用了相对路径,保存到NTFS 中的就是相对路径,不会隐式转换成绝对路径。
可以跨盘符,可以跨主机,可以使用UNC路径、网络驱动器。
在Explorer中删除symbolic link,不影响target。
删除target,symbolic link仍将存在,但失效了,变得不可用。
相关Win32 API:
CreateSymbolicLink() CreateSymbolicLinkTransacted()
创建:
mklink
注意不指定/D时创建file symbolic link,指定/D创建directory symbolic link。
查看:
junction.exe
该工具会区分显示"JUNCTION"与"SYMBOLIC LINK"。
删除:
del
对于
对于
没法"no follow symbolic link",下面这两个都有输出:
dir /A:-L /S "C:\Users" | findstr /C:"C:\Users\All Users" dir /A:-L /S "C:\Users" | grep -F "C:\Users\All Users"
"dir /?"可以看到L只是对应"Reparse Points"。
D: scz 2018-09-20 11:00
说个不相关的事:
$ echo "C:\Users\All Users\xxx" | findstr /C:"C:\Users\All Users" $ echo "C:\Users\All Users\xxx" | findstr /C:"C:\Users\All Users\x" $ echo "C:\Users\All Users\xxx" | grep -F "C:\Users\All Users" $ echo "C:\Users\All Users\xxx" | grep -F "C:\Users\All Users\x" "C:\Users\All Users\xxx"
上面这几个都会命中,但下面这两个不会命中:
$ echo "C:\Users\All Users\xxx" | findstr /C:"C:\Users\All Users\" $ echo "C:\Users\All Users\xxx" | grep -F "C:\Users\All Users\"
没有输出。结尾的\被特别处理了?不知是cmd的事,还是处理命令行参数的API的事? 比如:
kernel32!GetCommandLineW kernel32!GetCommandLineA KERNELBASE!GetCommandLineW KERNELBASE!GetCommandLineA shell32!CommandLineToArgvW
这事是版本相关的,前面都是在x64/Win7上测试。如果结尾是"\",情况会有不同。
注意"findstr /C"、"grep -F"的语义,已经尽可能避免转义处理。
Linux下用单引号时符合预期:
$ echo 'C:\Users\All Users\xxx' | grep -F 'C:\Users\All Users\' C:\Users\All Users\xxx
D: bluerust 2018-09-20 13:37
以前写批处理时被结尾的\坑过,尽量避免字符串结尾出现\。
用Process Monitor看了一眼findstr/grep拿到的参数,cmd对双引号中的字符串不做 任何处理就传给了findstr/grep,后面那些幺蛾子是findstr/grep自己搞出来的。
另做了一些实验,参看注释部分:
/
* Compile: cl /EHsc test_cmdline.c
*
* Desc :
* test_cmdline.exe "c:\hello\users"
* output:
* test_cmdline
* c:\hello\users
*
* Conclusion:
* No escape happened here, which means mainCRTStartup would respect the
* input feeded by user.
*
* For grep.exe compiled by mingw, the situation is different:
* grep -F "c:\users\"
*
* Stop at the main function of grep.exe, and check the argv array:
* 0:000> dqa ffffcc10
* 00000000ffffcc10 00000000
ffffcc40 "grep"
* 00000000ffffcc18 00000000
ffffcc45 "-F"
* 00000000ffffcc20 00000006
00028430 "c:\users\"
* 0:000> db 00000600028430 l10
* 00000006
00028430 63 3a 5c 75 73 65 72 73-5c 00 00 00 00 00 00 00 c:\users.......
*
* Obviously, before entering the main function the real entry function has
* perform an escape on the parameters.
/
include
include
include
include
pragma comment( lib, "user32.lib" )
pragma comment( lib, "kernel32.lib" )
int main( int argc, char *argv[] ) { int i;
for ( i = 0; i < argc; i++ )
{
_write( 1, argv[i], strlen( argv[i] ) );
_write( 1, "\n", 1 );
}
return 0;
}
前面都是些开放式讨论,未继续深究。