views:

670

answers:

3

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)?

+1  A: 

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.

Borzio
Good suggestion! I'll look into this if I don't find a more straight-forward solution. Thanks!
Abdullah Jibaly
I haven't heard of this app before your question and as a result, have downloaded it -- it's quite amazing, so thanks for asking the question. :) -- If I come across anything, I'll post it...
Borzio
+1  A: 

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.

crashmstr
Good that you had a chance to test it -- the environment issue was an unknown... :)
Borzio
Using COMSPEC here is a bit pointless, Win9x does not support NTFS (It does with the sysinternals add-on, but it does not have the chkntfs program)
Anders
No-one said anything about Win9x and without the COMSPEC, the execWait may not work. Simple as that.
crashmstr
sure it will, just hardcode cmd.exe. You are not supposed to use ExecWait when using redirection anyway, use nsExec or one of the 3rd party DosExec plugins on the nsis wiki
Anders
+2  A: 

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}
Anders
+1 for a good alternative to the external tool solution.
Jonas Gulle