来源:https://nsis-dev.github.io/NSIS-Forums/html/t-325143.html
更新:2024-05-04 修复源脚本错误,优化代码,翻译文档为中文。
用法:适用于 NSIS 的 Unicode 版本。
--------------------------------------------------------------------------------------
; 检查目标是否为硬链接
${IsHardLink} "${Path}" ${outVar}
; 检查目标是否为软链接(符号链接或连接点)
${IsSoftLink} "${Path}" ${outVar}
; 检查目标是否为硬链接或软链接
${IsLink} "${Path}" ${outVar}
--------------------------------------------------------------------------------------
; 创建硬链接(仅限文件,必须在同一卷上,且目标必须存在)
${CreateHardLink} "${Junction}" "${Target}" ${outVar}
; 为文件创建符号链接(Vista+,目标不需要存在,可以位于任何地方)
${CreateSymbolicLinkFile} "${Junction}" "${Target}" ${outVar}
; 首先尝试创建符号链接,如果失败,则尝试创建硬链接(仅限文件)
${CreateLinkFile} "${Junction}" "${Target}" ${outVar}
--------------------------------------------------------------------------------------
; 为文件夹创建符号链接(Vista+,目标不需要存在)
${CreateSymbolicLinkFolder} "${Junction}" "${Target}" ${outVar}
; 创建连接点(仅限文件夹,路径必须是绝对的,且目标应该存在)
${CreateJunction} "${Junction}" "${Target}" ${outVar}
; 首先尝试创建符号链接,如果失败,则尝试创建连接点(仅限文件夹)
${CreateLinkFolder} "${Junction}" "${Target}" ${outVar}
--------------------------------------------------------------------------------------
; 检查文件夹是否为连接点或符号链接,如果是,则删除它
${DeleteLinkFolder} "${Path}" ${outVar}
; 检查文件是否为符号链接或硬链接,如果是,则删除它
${DeleteLinkFile} "${Path}" ${outVar}
--------------------------------------------------------------------------------------
以上所有操作在失败时返回 "0",在成功时返回其他值(通常是 "1")
这三种类型的基本区别如下:
三者共性:
- 必须位于 NTFS 卷上(但目标不必须)
- 系统必须是 Windows 2000 或更新版本。
硬链接 (HardLink):
- 仅限文件;
- 链接和目标都必须位于同一卷上且必须存在;
- 路径必须是绝对的;
- 它与原始文件无法区分,实际上不像是链接,而更像是目标文件的另一个副本。
(除了当你编辑其中一个时,两个都会改变;但你需要删除两个才能真正删除该文件)
连接点 (Junction):
- 仅限文件夹;
- 在 WinXP 及更早版本中,如果在资源管理器中删除,目标也会被一并删除;
- 路径必须是绝对的,目标可以位于任何地方;
- 在 WinXP 上,如果目标不存在,则创建失败,在 Win7 上,即使目标不存在也会被创建。
符号链接 (SymbolicLink*):
- 仅 Vista 及更新版本;
- 支持文件和文件夹;
- 目标可以位于任何地方且不需要存在;
- 路径可以是相对的或绝对的。
头文件源代码:"Junction.nsh"
!ifndef JUNCTION_INCLUDED !define JUNCTION_INCLUDED !include FileFunc.nsh !include LogicLib.nsh !include Util.nsh !macro CreateParentFolder Path !verbose push !verbose 3 Push $1 ${GetParent} "${Path}" $1 CreateDirectory "$1" Pop $1 !verbose pop !macroend ; misc !define CreateParentFolder "!insertmacro CreateParentFolder" !macro IsSoftLink Path outVar !verbose push !verbose 3 Push "${Path}" ${CallArtificialFunction} IsSoftLink_ Pop ${outVar} !verbose pop !macroend !macro IsSoftLink_ Exch $0 ${GetFileAttributes} "$0" "REPARSE_POINT" $0 Exch $0 !macroend !macro IsHardLink Path outVar !verbose push !verbose 3 Push "${Path}" ${CallArtificialFunction} IsHardLink_ Pop ${outVar} !verbose pop !macroend !macro IsHardLink_ Push $0 Exch Exch $1 System::Call "kernel32::CreateFileW(w `$1`, i 0x40000000, i 0, i 0, i 3, i 0, i 0) i .r0" StrCmp $0 "-1" 0 +3 StrCpy $0 0 goto is_hardlink_end System::Call "*(&i256 0) i. r1" System::Call "kernel32::GetFileInformationByHandle(i r0, i r1) i .s" System::Call "kernel32::CloseHandle(i r0) i.r0" Pop $0 StrCmp $0 0 is_hardlink_end System::Call "*$1(&i40 0, &i4 .r0)" StrCmp $0 0 is_hardlink_end IntOp $0 $0 - 1 is_hardlink_end: Pop $1 Exch $0 !macroend !macro IsLink Path outVar !verbose push !verbose 3 ${IsSoftLink} "${Path}" ${outVar} ${If} ${outVar} == 0 ${IsHardLink} "${Path}" ${outVar} ${EndIf} !verbose pop !macroend ; info !define IsLink "!insertmacro IsLink" !define IsSoftLink "!insertmacro IsSoftLink" !define IsHardLink "!insertmacro IsHardLink" !macro CreateSymbolicLinkFile Junction Target outVar !verbose push !verbose 3 ${CreateParentFolder} "${Junction}" System::Call "kernel32::CreateSymbolicLinkW(w `${Junction}`, w `${Target}`, i 0) i .s" Pop ${outVar} !verbose pop !macroend !macro CreateHardLink Junction Target outVar !verbose push !verbose 3 ${CreateParentFolder} "${Junction}" System::Call "kernel32::CreateHardLinkW(w `${Junction}`, w `${Target}`, i 0) i .s" Pop ${outVar} !verbose pop !macroend !macro CreateLinkFile Junction Target outVar !verbose push !verbose 3 ${CreateSymbolicLinkFile} "${Junction}" "${Target}" ${outVar} ${If} ${outVar} == 0 ${CreateHardLink} "${Junction}" "${Target}" ${outVar} ${EndIf} !verbose pop !macroend !macro DeleteLinkFile Path outVar !verbose push !verbose 3 ${IsLink} "${Path}" ${outVar} ${If} ${outVar} != 0 SetFileAttributes "${Path}" "NORMAL" System::Call "kernel32::DeleteFileW(w `${Path}`) i.s" Pop ${outVar} ${EndIf} !verbose pop !macroend ; files !define CreateHardLink "!insertmacro CreateHardLink" !define CreateSymbolicLinkFile "!insertmacro CreateSymbolicLinkFile" !define CreateLinkFile "!insertmacro CreateLinkFile" !define DeleteLinkFile "!insertmacro DeleteLinkFile" !macro CreateJunction Junction Target outVar !verbose push !verbose 3 Push "${Junction}" Push "${Target}" ${CallArtificialFunction} CreateJunction_ Pop ${outVar} !verbose pop !macroend !macro CreateJunction_ Push $0 Exch 2 Exch Exch $4 Exch Exch $5 Push $1 Push $2 Push $3 Push $6 CreateDirectory "$5" System::Call "kernel32::CreateFileW(w `$5`, i 0x40000000, i 0, i 0, i 3, i 0x02200000, i 0) i .r6" StrCmp $0 "-1" 0 +4 StrCpy $0 0 RMDir "$5" goto create_junction_end CreateDirectory "$4" ; Windows XP requires that the destination exists StrCpy $4 "\??\$4" StrLen $0 $4 IntOp $0 $0 * 2 IntOp $1 $0 + 2 IntOp $2 $1 + 10 IntOp $3 $1 + 18 System::Call "*(i 0xA0000003, &i4 $2, &i2 0, &i2 $0, &i2 $1, &i2 0, &w$1 `$4`, &i2 0)i.r2" System::Call "kernel32::DeviceIoControl(i r6, i 0x900A4, i r2, i r3, i 0, i 0, *i r4r4, i 0) i.r0" System::Call "kernel32::CloseHandle(i r6) i.r1" StrCmp $0 "0" 0 +2 RMDir "$5" create_junction_end: Pop $6 Pop $3 Pop $2 Pop $1 Pop $5 Pop $4 Exch $0 !macroend !macro CreateSymbolicLinkFolder Junction Target outVar !verbose push !verbose 3 ${CreateParentFolder} "${Junction}" System::Call "kernel32::CreateSymbolicLinkW(w `${Junction}`, w `${Target}`, i 1) i .s" Pop ${outVar} !verbose pop !macroend !macro CreateLinkFolder Junction Target outVar !verbose push !verbose 3 ${CreateSymbolicLinkFolder} "${Junction}" "${Target}" ${outVar} ${If} ${outVar} == 0 ${CreateJunction} "${Junction}" "${Target}" ${outVar} ${EndIf} !verbose pop !macroend !macro DeleteLinkFolder Path outVar !verbose push !verbose 3 ${IsSoftLink} "${Path}" ${outVar} ${If} ${outVar} != 0 SetFileAttributes "${Path}" "NORMAL" System::Call "kernel32::RemoveDirectoryW(w `${Path}`) i.s" Pop ${outVar} ${EndIf} !verbose pop !macroend ; folders !define CreateJunction "!insertmacro CreateJunction" !define CreateSymbolicLinkFolder "!insertmacro CreateSymbolicLinkFolder" !define CreateLinkFolder "!insertmacro CreateLinkFolder" !define DeleteLinkFolder "!insertmacro DeleteLinkFolder" !endif
文章评论