IsWritable

From NSIS Wiki
Jump to navigationJump to search
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