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 // 这是cmd.exe内部命令 fsutil.exe hardlink create 查看: fsutil.exe hardlink list 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 // 生成的Reparse Data相比junction.exe要多 linkd.exe // Windows Resource Kits 查看: dir /A:L /S dir /A:-L /S // no follow junction point fsutil.exe reparsepoint query // 有Reparse Data的16进制转储 linkd.exe // 不能查看junction.exe生成的 删除: fsutil.exe reparsepoint delete // 不建议使用 它这个行为不是我们期望的效果,比如下有普通文件,上述命令 会删除下的普通文件,但不会删除,同时 下的普通文件仍然存在。这个效果我不能理解。在Explorer中操 作无法达到这种效果。 linkd.exe /D // 可以删除junction.exe生成的 sysinternals的junction.exe: junction.exe // 创建 junction.exe // 查看 junction.exe -q -s // 递归查看 junction.exe -d // 删除 我猜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 mklink /D 注意不指定/D时创建file symbolic link,指定/D创建directory symbolic link。 查看: junction.exe 该工具会区分显示"JUNCTION"与"SYMBOLIC LINK"。 删除: del rmdir 对于,右键属性中可以直接看出来。 对于,右键属性常规页可以看到"目标",并且属性 中还多了一个快捷方式页。 没法"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 * 00000000`ffffcc10 00000000`ffffcc40 "grep" * 00000000`ffffcc18 00000000`ffffcc45 "-F" * 00000000`ffffcc20 00000006`00028430 "c:\users\" * 0:000> db 000006`00028430 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; } -------------------------------------------------------------------------- 前面都是些开放式讨论,未继续深究。