Question

I'm creating an installer with NSIS for a program that needs to run on an NTFS volume. How do I detect if the install to path is on an NTFS volume and act accordingly (show a help/warning message)?

Was it helpful?

Solution

Using external tools is not always a good idea (Not every command line tool exists on the Home versions of windows ) It's always better to call the correct API directly with the system plug in.

!include LogicLib.nsh

StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i,t.r1,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
    MessageBox mb_ok "fs=$1"
${EndIf}

But in this case, you should not be checking the file system type, but you should look for the actual feature you need (compression,encryption,junctions,sparse files etc)

!define FILE_SUPPORTS_ENCRYPTION 0x00020000
!define FILE_READ_ONLY_VOLUME 0x00080000
!define FILE_VOLUME_QUOTAS 0x00000020

!macro MakeBitFlagYesNo flags bit outvar
IntOp ${outvar} ${flags} & ${bit}
${IfThen} ${outvar} <> 0 ${|} StrCpy ${outvar} "Yes" ${|}
${IfThen} ${outvar} == 0 ${|} StrCpy ${outvar} "No" ${|}
!macroend

StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
    !insertmacro MakeBitFlagYesNo $1 ${FILE_SUPPORTS_ENCRYPTION} $2
    !insertmacro MakeBitFlagYesNo $1 ${FILE_READ_ONLY_VOLUME} $3
    !insertmacro MakeBitFlagYesNo $1 ${FILE_VOLUME_QUOTAS} $4
    MessageBox mb_ok "flags=$1 $\nFILE_SUPPORTS_ENCRYPTION=$2$\nFILE_READ_ONLY_VOLUME=$3$\nFILE_VOLUME_QUOTAS=$4"
${EndIf}

OTHER TIPS

I'm not familiar with NSIS, but you may find this little "DOS" trick helpful.

I did notice that it is possible to open a file with NSIS, so this may help --

chkntfs c: | find "file system" > yourfile.abc

CHKNTFS is a utility for managing the CHKDSK operations, but if you run the command with no command line switches, it simply reports the results.

the "C:" is the drive you're interested in --

You can run this from a command prompt to see the result, without the "> yourfile.abc" part, of course, which is what directs the output into that file.

Before anyone down votes this, I just offer it as a thought provoking SUGGESTION, perhaps sparking the real solution and remember SO motto -- be KIND ... lol ...

EDIT: this snippet may help -- I have no way to really TEST this -- THIS IS COMPILE TIME USAGE -- and you will most likely want RUN-TIME ... BUT, it may give you an idea ...

I "assume" there isn't a define already named NTFS -- if so, change this accordingly. The first call CREATES the include file, the second APPENDS to it (the double > )... The /C option for FIND simply COUNTS the number lines containing the search item. Hence, the 0 or 1 result.

!system 'echo "!define NTFS=" > newinclude.nsh'
!system 'chkntfs c: | find /c "NTFS" >> newinclude.nsh'
!include newinclude.nsh
!ifdef NTFS
  !echo "NTFS is defined and value should reflect accordingly; 0=NO, 1=Yes it is NTFS"
!endif

EDIT: (again, lol)

here's a snippet that will set an ENVIRONMENT variable, which from what I can tell, should be rather easy to read during run-time -- you could construct a variable to execute, replacing the drive letter accordingly.

ExecWait 'chkntfs c: | find /c "NTFS"  > tempfile.abc'
ExecWait 'set /p NTFS= < tempfile.abc'
Exec     'del tempfile.abc'

Now, an environment variable called NTFS should hold a 0 if not NTFS and 1 if the volume being inspected IS NTFS.

Or directly

ExecWait 'chkntfs c: | find /c "NTFS"' $0

$0 holds the return code; The results are kind of backwards as this is the ERROR return code. If 0 you HAVE NTFS and > 0 means NO NTFS.

Your test would need to be at run-time, so Borzio's answer would not work by itself.

It also looks like the ExecWait command does not allow for redirection, so it would not work to execute it that way and then check the contents of a file.

It looks to me like your best options would be to pick one of:

  • make a batch file that would run chkntfs and then set the error level based on the result
  • write a C/C++/VB/etc. app that would run chkntfs and then set the error level based on the result
  • write a C/C++/VB/etc. app that would use Win32 APIs to determine the filesystem
  • write a plug-in for NSIS that would use Win32 APIs to determine the filesystem

Edit: Borzio updated his before I finished mine :)

You might need to add something I found on the Winamp forums: ExecWait with file redirection

  ExpandEnvStrings $1 %COMSPEC%
  ExecWait '"$1" /C chkntfs c: | find /c "NTFS"' $0

Without the ExpandEnvStrings $1 %COMSPEC%, it was not working on my system to generate a redirected file.

I've tested the above, and it does work, 0 for NTFS and 1 for non NTFS.

The only possible drawback for this method is that a command windows pops up briefly during the code execution.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top