forked from mirror/go-ethereum
build: safe update of PATH on Windows (#3419)
NSIS has a default MAX_STR_LEN of 1024. If $ENV{PATH} is longer the returned string is truncated to an empty string. Its then not possible to distinguis between the variable not set or too long. As a result the variable is set with the location where geth and/or dev tools are installed. This may override any previous set values.release/1.5
parent
4e36b1e3da
commit
4f9ccdd70f
@ -0,0 +1,153 @@ |
||||
!include "WinMessages.nsh" |
||||
|
||||
; see https://support.microsoft.com/en-us/kb/104011 |
||||
!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' |
||||
; HKEY_LOCAL_MACHINE = 0x80000002 |
||||
|
||||
; AddToPath - Appends dir to PATH |
||||
; (does not work on Win9x/ME) |
||||
; |
||||
; Usage: |
||||
; Push "dir" |
||||
; Call AddToPath |
||||
Function AddToPath |
||||
Exch $0 |
||||
Push $1 |
||||
Push $2 |
||||
Push $3 |
||||
Push $4 |
||||
|
||||
; NSIS ReadRegStr returns empty string on string overflow |
||||
; Native calls are used here to check actual length of PATH |
||||
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3) |
||||
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4" |
||||
IntCmp $4 0 0 done done |
||||
|
||||
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2)) |
||||
; RegCloseKey($3) |
||||
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4" |
||||
System::Call "advapi32::RegCloseKey(i $3)" |
||||
|
||||
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA |
||||
DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}" |
||||
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}" |
||||
Goto done |
||||
|
||||
IntCmp $4 0 +5 ; $4 != NO_ERROR |
||||
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND |
||||
DetailPrint "AddToPath: unexpected error code $4" |
||||
Goto done |
||||
StrCpy $1 "" |
||||
|
||||
; Check if already in PATH |
||||
Push "$1;" |
||||
Push "$0;" |
||||
Call StrStr |
||||
Pop $2 |
||||
StrCmp $2 "" 0 done |
||||
Push "$1;" |
||||
Push "$0\;" |
||||
Call StrStr |
||||
Pop $2 |
||||
StrCmp $2 "" 0 done |
||||
|
||||
; Prevent NSIS string overflow |
||||
StrLen $2 $0 |
||||
StrLen $3 $1 |
||||
IntOp $2 $2 + $3 |
||||
IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";") |
||||
IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0 |
||||
DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}" |
||||
MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}." |
||||
Goto done |
||||
|
||||
; Append dir to PATH |
||||
DetailPrint "Add to PATH: $0" |
||||
StrCpy $2 $1 1 -1 |
||||
StrCmp $2 ";" 0 +2 |
||||
StrCpy $1 $1 -1 ; remove trailing ';' |
||||
StrCmp $1 "" +2 ; no leading ';' |
||||
StrCpy $0 "$1;$0" |
||||
|
||||
WriteRegExpandStr ${Environ} "PATH" $0 |
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
||||
|
||||
done: |
||||
Pop $4 |
||||
Pop $3 |
||||
Pop $2 |
||||
Pop $1 |
||||
Pop $0 |
||||
FunctionEnd |
||||
|
||||
|
||||
; RemoveFromPath - Removes dir from PATH |
||||
; |
||||
; Usage: |
||||
; Push "dir" |
||||
; Call RemoveFromPath |
||||
Function un.RemoveFromPath |
||||
Exch $0 |
||||
Push $1 |
||||
Push $2 |
||||
Push $3 |
||||
Push $4 |
||||
Push $5 |
||||
Push $6 |
||||
|
||||
; NSIS ReadRegStr returns empty string on string overflow |
||||
; Native calls are used here to check actual length of PATH |
||||
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3) |
||||
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4" |
||||
IntCmp $4 0 0 done done |
||||
|
||||
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2)) |
||||
; RegCloseKey($3) |
||||
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4" |
||||
System::Call "advapi32::RegCloseKey(i $3)" |
||||
|
||||
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA |
||||
DetailPrint "RemoveFromPath: original length $2 > ${NSIS_MAX_STRLEN}" |
||||
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}" |
||||
Goto done |
||||
|
||||
IntCmp $4 0 +5 ; $4 != NO_ERROR |
||||
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND |
||||
DetailPrint "RemoveFromPath: unexpected error code $4" |
||||
Goto done |
||||
StrCpy $1 "" |
||||
|
||||
; length < ${NSIS_MAX_STRLEN} -> ReadRegStr can be used |
||||
ReadRegStr $1 ${Environ} "PATH" |
||||
StrCpy $5 $1 1 -1 |
||||
StrCmp $5 ";" +2 |
||||
StrCpy $1 "$1;" ; ensure trailing ';' |
||||
Push $1 |
||||
Push "$0;" |
||||
Call un.StrStr |
||||
Pop $2 ; pos of our dir |
||||
StrCmp $2 "" done |
||||
|
||||
DetailPrint "Remove from PATH: $0" |
||||
StrLen $3 "$0;" |
||||
StrLen $4 $2 |
||||
StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove |
||||
StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove |
||||
StrCpy $3 "$5$6" |
||||
StrCpy $5 $3 1 -1 |
||||
StrCmp $5 ";" 0 +2 |
||||
StrCpy $3 $3 -1 ; remove trailing ';' |
||||
WriteRegExpandStr ${Environ} "PATH" $3 |
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 |
||||
|
||||
done: |
||||
Pop $6 |
||||
Pop $5 |
||||
Pop $4 |
||||
Pop $3 |
||||
Pop $2 |
||||
Pop $1 |
||||
Pop $0 |
||||
FunctionEnd |
||||
|
||||
|
Loading…
Reference in new issue