NSIS 创建软链接、硬链接和符号链接

2024-05-04 1169点热度 0人点赞 0条评论

来源: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

南陇居士

NLJS.SITE - 分享 · 记录

文章评论