<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://nsis.sourceforge.io/mediawiki/index.php?action=history&amp;feed=atom&amp;title=IsWritable</id>
	<title>IsWritable - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://nsis.sourceforge.io/mediawiki/index.php?action=history&amp;feed=atom&amp;title=IsWritable"/>
	<link rel="alternate" type="text/html" href="https://nsis.sourceforge.io/mediawiki/index.php?title=IsWritable&amp;action=history"/>
	<updated>2026-07-21T01:57:48Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://nsis.sourceforge.io/mediawiki/index.php?title=IsWritable&amp;diff=10142&amp;oldid=prev</id>
		<title>IoDream at 18:45, 21 April 2006</title>
		<link rel="alternate" type="text/html" href="https://nsis.sourceforge.io/mediawiki/index.php?title=IsWritable&amp;diff=10142&amp;oldid=prev"/>
		<updated>2006-04-21T18:45:45Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{PageAuthor|IoDream}}&lt;br /&gt;
&lt;br /&gt;
A function to avoid users installing software on read-only places.&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
&lt;br /&gt;
One of my customer complained that if you installed my software in a directory he doesn&amp;#039;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.&lt;br /&gt;
&lt;br /&gt;
It&amp;#039;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.&lt;br /&gt;
&lt;br /&gt;
== Changelog ==&lt;br /&gt;
&lt;br /&gt;
; 2006-04-21 : Initial version.&lt;br /&gt;
&lt;br /&gt;
== Licence ==&lt;br /&gt;
&lt;br /&gt;
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).&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
&lt;br /&gt;
The verification is done in the &amp;#039;&amp;#039;&amp;#039;IsWritable&amp;#039;&amp;#039;&amp;#039; function, but this one needs other functions: &amp;#039;&amp;#039;&amp;#039;GetParent&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;GetFileAttributes&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
=== GetParent function ===&lt;br /&gt;
&lt;br /&gt;
This is the same function you can find in the NSIS manual (maybe this is an improved version I grabbed somewhere, I don&amp;#039;t remember). I added useless comments, and improved the call with a macro.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;highlight-nsis&amp;gt;&lt;br /&gt;
;----------------------------------------------------------------------------&lt;br /&gt;
; Support functions.&lt;br /&gt;
&lt;br /&gt;
;____________________________________________________________________________&lt;br /&gt;
;                            GetParent&lt;br /&gt;
;____________________________________________________________________________&lt;br /&gt;
;&lt;br /&gt;
; Get the parent directory (only syntaxically).&lt;br /&gt;
; In fact it only truncates the path to the latest &amp;quot;\&amp;quot; (excluded).&lt;br /&gt;
;&lt;br /&gt;
;Syntax:&lt;br /&gt;
;${GetParent} &amp;quot;[Path]&amp;quot; $res&lt;br /&gt;
; &lt;br /&gt;
;&amp;quot;[Path]&amp;quot;          ; The path to check&lt;br /&gt;
;                  ;&lt;br /&gt;
;$res              ; Result:&lt;br /&gt;
;                  ;    $res=the parent directory of [Path]&lt;br /&gt;
;&lt;br /&gt;
;Example1:&lt;br /&gt;
;&lt;br /&gt;
;Section&lt;br /&gt;
;  ${GetParent} &amp;quot;C:\Program Files\Pl0p&amp;quot; $R0&lt;br /&gt;
;  ; at this point $R0 will equal &amp;quot;C:\Program Files&amp;quot;&lt;br /&gt;
;SectionEnd&lt;br /&gt;
;&lt;br /&gt;
;Example2:&lt;br /&gt;
;&lt;br /&gt;
;Section&lt;br /&gt;
;  ${GetParent} &amp;quot;C:\Program Files&amp;quot; $R1&lt;br /&gt;
;  ; at this point $R1 will equal &amp;quot;C:&amp;quot;&lt;br /&gt;
;SectionEnd&lt;br /&gt;
;&lt;br /&gt;
;Example3:&lt;br /&gt;
;&lt;br /&gt;
;Section&lt;br /&gt;
;  ${GetParent} &amp;quot;C:&amp;quot; $R7&lt;br /&gt;
;  ; at this point $R7 will equal &amp;quot;C:&amp;quot;&lt;br /&gt;
;SectionEnd&lt;br /&gt;
;&lt;br /&gt;
Function GetParent&lt;br /&gt;
  !define GetParent `!insertmacro GetParentCall`&lt;br /&gt;
&lt;br /&gt;
  !macro GetParentCall _PATH _RESULT&lt;br /&gt;
    Push `${_PATH}`&lt;br /&gt;
    Call GetParent&lt;br /&gt;
    Pop ${_RESULT}&lt;br /&gt;
  !macroend&lt;br /&gt;
&lt;br /&gt;
  # Makes $R0 contains the input that was at the top of stack.&lt;br /&gt;
  Exch $R0&lt;br /&gt;
  # Saves $R1-$R3 to the stack ($R0 was save in the previous step).&lt;br /&gt;
  Push $R1&lt;br /&gt;
  Push $R2&lt;br /&gt;
  Push $R3&lt;br /&gt;
&lt;br /&gt;
  # Set $R1 to 0.&lt;br /&gt;
  StrCpy $R1 0&lt;br /&gt;
  # Set $R2 to the length of the input.&lt;br /&gt;
  StrLen $R2 $R0&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
  # Inc $R1.&lt;br /&gt;
  IntOp $R1 $R1 + 1&lt;br /&gt;
  # If $R1 exceeds the length of the input then goto get:&lt;br /&gt;
  IntCmp $R1 $R2 get 0 get&lt;br /&gt;
  # Puts in $R3 the $R1-th char (from the right) of the input.&lt;br /&gt;
  StrCpy $R3 $R0 1 -$R1&lt;br /&gt;
  # If this char is &amp;quot;\&amp;quot; then goto get:&lt;br /&gt;
  StrCmp $R3 &amp;quot;\&amp;quot; get&lt;br /&gt;
  # Go back to the start of the loop:&lt;br /&gt;
  Goto loop&lt;br /&gt;
&lt;br /&gt;
get:&lt;br /&gt;
  # Copies to output the input string from the first to the $R1-th char from the right.&lt;br /&gt;
  StrCpy $R0 $R0 -$R1&lt;br /&gt;
  &lt;br /&gt;
  # Restores $R1-$R3 from the stack.&lt;br /&gt;
  Pop $R3&lt;br /&gt;
  Pop $R2&lt;br /&gt;
  Pop $R1&lt;br /&gt;
  # Restores $R0 and puts the output at the top of the stack.&lt;br /&gt;
  Exch $R0&lt;br /&gt;
&lt;br /&gt;
FunctionEnd&lt;br /&gt;
&amp;lt;/highlight-nsis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GetFileAttributes function ===&lt;br /&gt;
&lt;br /&gt;
It is the [[GetFileAttributes]] function coded by [[User:Instructor|Instructor]]. This function is already included with the 2.07 header and later (see the [http://forums.winamp.com/showthread.php?postid=1859760#post1859760 latest version of headers]).&lt;br /&gt;
&lt;br /&gt;
=== IsWritable function ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;highlight-nsis&amp;gt;&lt;br /&gt;
;____________________________________________________________________________&lt;br /&gt;
;                            IsWritable&lt;br /&gt;
;____________________________________________________________________________&lt;br /&gt;
;&lt;br /&gt;
; Checks if a path exists and is writable by the user.&lt;br /&gt;
;&lt;br /&gt;
;Syntax:&lt;br /&gt;
;${IsWritable} &amp;quot;[Path]&amp;quot; $res&lt;br /&gt;
; &lt;br /&gt;
;&amp;quot;[Path]&amp;quot;          ; The path to check&lt;br /&gt;
;                  ;&lt;br /&gt;
;$res              ; Result:&lt;br /&gt;
;                  ;    $res=0   [Path] exists and is writable by the user.&lt;br /&gt;
;                  ;    $res=1   [Path] doesn&amp;#039;t exist or is read-only.&lt;br /&gt;
;&lt;br /&gt;
;Example1:&lt;br /&gt;
;&lt;br /&gt;
;Section&lt;br /&gt;
;  ${IsWritable} &amp;quot;C:\Program Files\Pl0p&amp;quot; $R0&lt;br /&gt;
;  ; at this point $R0 is 0 if &amp;quot;C:\Program Files\Pl0p&amp;quot; exists and is writable.&lt;br /&gt;
;  ; else $R0 is 1 (&amp;quot;C:\Program Files\Pl0p&amp;quot; doesn&amp;#039;t exists or is read-only).&lt;br /&gt;
;SectionEnd&lt;br /&gt;
;&lt;br /&gt;
Function IsWritable&lt;br /&gt;
  !define IsWritable `!insertmacro IsWritableCall`&lt;br /&gt;
&lt;br /&gt;
  !macro IsWritableCall _PATH _RESULT&lt;br /&gt;
    Push `${_PATH}`&lt;br /&gt;
    Call IsWritable&lt;br /&gt;
    Pop ${_RESULT}&lt;br /&gt;
  !macroend&lt;br /&gt;
&lt;br /&gt;
  Exch $R0&lt;br /&gt;
  Push $R1&lt;br /&gt;
&lt;br /&gt;
start:&lt;br /&gt;
  # Checks if $R0 is not empty.&lt;br /&gt;
  StrLen $R1 $R0&lt;br /&gt;
  StrCmp $R1 0 exit&lt;br /&gt;
  # Checks if $R0 exists and is a directory.&lt;br /&gt;
  ${GetFileAttributes} $R0 &amp;quot;DIRECTORY&amp;quot; $R1&lt;br /&gt;
  StrCmp $R1 1 direxists&lt;br /&gt;
  # $R0 doesn&amp;#039;t exist, getting parent.&lt;br /&gt;
  ${GetParent} $R0 $R0&lt;br /&gt;
  Goto start&lt;br /&gt;
&lt;br /&gt;
direxists:&lt;br /&gt;
  # Checks if $R0 is a directory.&lt;br /&gt;
  ${GetFileAttributes} $R0 &amp;quot;DIRECTORY&amp;quot; $R1&lt;br /&gt;
  StrCmp $R1 0 nook&lt;br /&gt;
  # Checks if $R0 is read-only.&lt;br /&gt;
  ${GetFileAttributes} $R0 &amp;quot;READONLY&amp;quot; $R1&lt;br /&gt;
  # $R1 contains 1 (ro then not ok) or 0 (rw then ok).&lt;br /&gt;
  Goto exit&lt;br /&gt;
&lt;br /&gt;
nook:&lt;br /&gt;
  StrCpy $R1 0&lt;br /&gt;
&lt;br /&gt;
exit:&lt;br /&gt;
  Exch&lt;br /&gt;
  Pop $R0&lt;br /&gt;
  Exch $R1&lt;br /&gt;
&lt;br /&gt;
FunctionEnd&lt;br /&gt;
&amp;lt;/highlight-nsis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
&lt;br /&gt;
Simply call the check inside the &amp;#039;&amp;#039;&amp;#039;.onVerifyInstDir&amp;#039;&amp;#039;&amp;#039; function. You can drop the following example directly into your code (with the above functions too).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;highlight-nsis&amp;gt;&lt;br /&gt;
Function .onVerifyInstDir&lt;br /&gt;
&lt;br /&gt;
  Push $R1&lt;br /&gt;
  ${IsWritable} $INSTDIR $R1&lt;br /&gt;
  IntCmp $R1 0 pathgood&lt;br /&gt;
  Pop $R1&lt;br /&gt;
  Abort&lt;br /&gt;
&lt;br /&gt;
pathgood:&lt;br /&gt;
  Pop $R1&lt;br /&gt;
&lt;br /&gt;
FunctionEnd&lt;br /&gt;
&amp;lt;/highlight-nsis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Disk, Path &amp;amp; File Functions]]&lt;/div&gt;</summary>
		<author><name>IoDream</name></author>
	</entry>
</feed>