IsWritable
Author: IoDream (talk, contrib) |
A function to avoid users installing software on read-only places.
Description
One of my customer complained that if you installed my software in a directory he doesn't have writing rights, the installer nevertheless tried to write then poped an cryptic message before aborting. So I wrote this function whose goal is to check user rights when selecting the destination directory.
It's working well, though it has not been checked by anybody else me. I know the code can be made nicer and faster; it is only my first attempt to code a NSIS script.
Changelog
- 2006-04-21
- Initial version.
Licence
This code is under BSD Licence. So you can do whatever you want with it, but it would be nice if you give some feedback (ideas, improvements, thanks, etc).
Code
The verification is done in the IsWritable function, but this one needs other functions: GetParent and GetFileAttributes.
GetParent function
This is the same function you can find in the NSIS manual (maybe this is an improved version I grabbed somewhere, I don't remember). I added useless comments, and improved the call with a macro.
;---------------------------------------------------------------------------- ; Support functions. ;____________________________________________________________________________ ; GetParent ;____________________________________________________________________________ ; ; Get the parent directory (only syntaxically). ; In fact it only truncates the path to the latest "\" (excluded). ; ;Syntax: ;${GetParent} "[Path]" $res ; ;"[Path]" ; The path to check ; ; ;$res ; Result: ; ; $res=the parent directory of [Path] ; ;Example1: ; ;Section ; ${GetParent} "C:\Program Files\Pl0p" $R0 ; ; at this point $R0 will equal "C:\Program Files" ;SectionEnd ; ;Example2: ; ;Section ; ${GetParent} "C:\Program Files" $R1 ; ; at this point $R1 will equal "C:" ;SectionEnd ; ;Example3: ; ;Section ; ${GetParent} "C:" $R7 ; ; at this point $R7 will equal "C:" ;SectionEnd ; Function GetParent !define GetParent `!insertmacro GetParentCall` !macro GetParentCall _PATH _RESULT Push `${_PATH}` Call GetParent Pop ${_RESULT} !macroend # Makes $R0 contains the input that was at the top of stack. Exch $R0 # Saves $R1-$R3 to the stack ($R0 was save in the previous step). Push $R1 Push $R2 Push $R3 # Set $R1 to 0. StrCpy $R1 0 # Set $R2 to the length of the input. StrLen $R2 $R0 loop: # Inc $R1. IntOp $R1 $R1 + 1 # If $R1 exceeds the length of the input then goto get: IntCmp $R1 $R2 get 0 get # Puts in $R3 the $R1-th char (from the right) of the input. StrCpy $R3 $R0 1 -$R1 # If this char is "\" then goto get: StrCmp $R3 "\" get # Go back to the start of the loop: Goto loop get: # Copies to output the input string from the first to the $R1-th char from the right. StrCpy $R0 $R0 -$R1 # Restores $R1-$R3 from the stack. Pop $R3 Pop $R2 Pop $R1 # Restores $R0 and puts the output at the top of the stack. Exch $R0 FunctionEnd
GetFileAttributes function
It is the GetFileAttributes function coded by Instructor. This function is already included with the 2.07 header and later (see the latest version of headers).
IsWritable function
;____________________________________________________________________________ ; IsWritable ;____________________________________________________________________________ ; ; Checks if a path exists and is writable by the user. ; ;Syntax: ;${IsWritable} "[Path]" $res ; ;"[Path]" ; The path to check ; ; ;$res ; Result: ; ; $res=0 [Path] exists and is writable by the user. ; ; $res=1 [Path] doesn't exist or is read-only. ; ;Example1: ; ;Section ; ${IsWritable} "C:\Program Files\Pl0p" $R0 ; ; at this point $R0 is 0 if "C:\Program Files\Pl0p" exists and is writable. ; ; else $R0 is 1 ("C:\Program Files\Pl0p" doesn't exists or is read-only). ;SectionEnd ; Function IsWritable !define IsWritable `!insertmacro IsWritableCall` !macro IsWritableCall _PATH _RESULT Push `${_PATH}` Call IsWritable Pop ${_RESULT} !macroend Exch $R0 Push $R1 start: # Checks if $R0 is not empty. StrLen $R1 $R0 StrCmp $R1 0 exit # Checks if $R0 exists and is a directory. ${GetFileAttributes} $R0 "DIRECTORY" $R1 StrCmp $R1 1 direxists # $R0 doesn't exist, getting parent. ${GetParent} $R0 $R0 Goto start direxists: # Checks if $R0 is a directory. ${GetFileAttributes} $R0 "DIRECTORY" $R1 StrCmp $R1 0 nook # Checks if $R0 is read-only. ${GetFileAttributes} $R0 "READONLY" $R1 # $R1 contains 1 (ro then not ok) or 0 (rw then ok). Goto exit nook: StrCpy $R1 0 exit: Exch Pop $R0 Exch $R1 FunctionEnd
Usage
Simply call the check inside the .onVerifyInstDir function. You can drop the following example directly into your code (with the above functions too).
Function .onVerifyInstDir Push $R1 ${IsWritable} $INSTDIR $R1 IntCmp $R1 0 pathgood Pop $R1 Abort pathgood: Pop $R1 FunctionEnd