WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

System Info

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Available Space


Question:

According to Microsoft, the definition of "Available" Space is contiguous, non-fragmentted space, and the way that they suggest calculating the Available Space is by using FSCTL_QUERY_ALLOCATED_RANGES. This would be the logic:

First, to get the allocated vs. free statistics, use FSCTL_GET_NTFS_VOLUME_DATA to obtain the volume's current parameters. Below are the member variables of interest.

Members
=========================================================================
NumberSectors - Number of sectors in the specified volume. 
TotalClusters - Number of used and free clusters in the specified volume. 
FreeClusters  - Number of free clusters in the specified volume. 
TotalReserved - Number of reserved clusters in the specified volume. 
=========================================================================
Next, calculate Fragged Space:
FraggedSpace  = Total byte count of all fragmented files.
FraggedSpace can be queried by enumerating all files on the drive and querying the file extents with FSCTL_QUERY_ALLOCATED_RANGES.

If the file is fragmented, then add its byte count to FraggedSpace.

  AllocatedClusters = (TotalClusters - FreeClusters )
  PercentAllocated  = AllocatedClusters / TotalClusters  * 100
  PercentFragmented = 100 * FraggedSpace /BytesPerCluster / AllocatedClusters
So then, if PercentFragmented > .85 I shouldn't launch Defrag, because the Low-Available-Space confirmation box will pop-up.....

Additional information on FSCTL_QUERY_ALLOCATED_RANGES is available on msdn at: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/fsctl_query_allocated_ranges.asp Would it be possible for Winbatch to follow this suggested logic to return the PercentFragmented?

Answer:

Here is a UDF I put together that returns Volumne information in a Huge number format. THis requires the use of the Huge Math Extender.
#DefineFunction GET_NTFS_VOLUME_DATA(DriveLetterAndColon, flag)
   ;***************************************************************************
   ;** Purpose: Function for getting 'NTFS VOLUME DATA'
   ;**
   ;** Inputs:
   ;** (s) DriveLetterAndColon should be two characters WITHOUT a trailing backslash, ex: "D:"
   ;**
   ;** (i) Flag allows you to choose the data you want returned
   ;**      VolumeSerialNumber  = 0
   ;**      NumberSectors = 1
   ;**      TotalClusters  = 2
   ;**      FreeClusters  = 3
   ;**      TotalReserved = 4
   ;**      BytesPerSector = 5
   ;**      BytesPerCluster = 6
   ;**      BytesPerFileRecord = 7
   ;**      ClustersPerFileRec = 8
   ;**      MftValidDataLength = 9
   ;**      MftStartLcn = 10
   ;**      Mft2StartLcn = 11
   ;**      MftZoneStart = 12
   ;**      MftZoneEnd = 13
   ;**
   ;**  NOTES:
   ;   !!!! IMPORTANT !!!!!
   ;   !!!!!!!!! Returns GET_NTFS_VOLUME_DATA as a Huge Number !!!!!!!!!!
   ;
   ;     CreateFile will probably fail on Win9x systems so this function is only intended for use on NT 4 and greater
   ;     You can use the CreateFile function to open a disk drive or a partition on a disk drive. The function returns a
   ;     handle to the disk device. That handle can be used with the DeviceIoControl function. The following list shows the
   ;     requirements that must be met for such a call to succeed:
   ;
   ;      - The caller must have administrative privileges for the operation to succeed on a hard disk drive.
   ;      - When opening a physical drive x, the lpFileName string should be the following form: \\.\PHYSICALDRIVE<x>. Hard disk numbers start at 0 (zero).
   ;      - The dwCreationDisposition parameter must have the OPEN_EXISTING value.
   ;      - When opening a disk or a partition on a hard disk, you must set the FILE_SHARE_WRITE flag in the dwShareMode parameter.
   ;**
   ;** Outputs:
   ;** (h) Returns GET_NTFS_VOLUME_DATA (based on request flag) as a Huge Number
   ;**
   ;** Author: Deana Falk
   ;** Revisions: July 13th 2006
   ;***************************************************************************
   IntControl(73, 1, 0, 0, 0)

   INVALID_HANDLE_VALUE = -1
   OPEN_EXISTING = 3
   FILE_ATTRIBUTE_NORMAL = 128
   FILE_SHARE_WRITE = 2
   FILE_SHARE_READ = 1
   FILE_READ_ATTRIBUTES  = 128
   GENERIC_READ = 2147483648
   FSCTL_GET_NTFS_VOLUME_DATA = 589924


   drivepath = StrCat("\\.\", DriveLetterAndColon)
   DaDll=StrCat(DirWindows(1),"kernel32.dll")
   hDrive=DllCall(DaDll,long:"CreateFileA",lpstr:drivepath,long:GENERIC_READ,long:FILE_SHARE_READ|FILE_SHARE_WRITE , lpnull, long:OPEN_EXISTING, long:0, lpnull)
     LastErr = DllLastError()
   If hDrive == INVALID_HANDLE_VALUE
       Message("CreateFileA Failed with Error",LastErr)
       Return 0
   EndIf

   NTFS_VOLUME_DATA_BUFFERSz = 1096 ; 96 byte structure plus 1000 to be safe, if there is extended data in the buffer
   lpNTFS_VOLUME_DATA_BUFFER = BinaryAlloc(NTFS_VOLUME_DATA_BUFFERSz)

   lpReturnedBytes = BinaryAlloc(4)
   Rslt = DllCall(DaDll,long:"DeviceIoControl",long:hDrive, long:FSCTL_GET_NTFS_VOLUME_DATA, lpnull, long:0, lpbinary:lpNTFS_VOLUME_DATA_BUFFER, long:NTFS_VOLUME_DATA_BUFFERSz, lpbinary:lpReturnedBytes, lpnull)
   LastErr = DllLastError()
   If Rslt == 0
      ;bytes = BinaryPeek4(lpReturnedBytes, 0 ); checks size of buffer required if ERROR_INSUFFUCENT_BUFFER
      Message("DeviceIoControl Failed with Error",LastErr)
      Return 0
   EndIf

   Switch flag
      Case 0 ;VolumeSerialNumber
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 0 ))
         Break
      Case 1 ;NumberSectors
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 8 ))
         Break
      Case 2 ;TotalClusters
         retval  = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 16 ))
         Break
      Case 3 ;FreeClusters
         retval  = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 24 ))
         Break
      Case 4 ;TotalReserved
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 32 ))
         Break
      Case 5 ;BytesPerSector
         retval = BinaryPeek4(lpNTFS_VOLUME_DATA_BUFFER, 40 )
         Break
      Case 6 ;BytesPerCluster
         retval = BinaryPeek4(lpNTFS_VOLUME_DATA_BUFFER, 44 )
         Break
      Case 7 ;BytesPerFileRecordSegment
         retval = BinaryPeek4(lpNTFS_VOLUME_DATA_BUFFER, 48 )
         Break
      Case 8 ;ClustersPerFileRecordSegment
         retval = BinaryPeek4(lpNTFS_VOLUME_DATA_BUFFER, 52 )
         Break
      Case 9 ;MftValidDataLength
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 56 ))
         Break
      Case 10 ;MftStartLcn
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 64 ))
         Break
      Case 11 ;Mft2StartLcn
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 72 ))
         Break
      Case 12 ;MftZoneStart
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 80 ))
         Break
      Case 13 ;MftZoneEnd
         retval = UDFCvtFloatToHuge(BinaryPeekFlt(lpNTFS_VOLUME_DATA_BUFFER, 88 ))
         Break
   EndSwitch
   BinaryFree(lpNTFS_VOLUME_DATA_BUFFER)
   BinaryFree(lpReturnedBytes)
   DllCall(DaDll,long:"CloseHandle",long:hDrive)  ;Clean up after outselves

   Return retval


   :WBERRORHANDLER
   If IsDefined(hDrive)
      If hDrive !=0 Then DllCall(DaDll,long:"CloseHandle",long:hDrive)
   EndIf
   If IsDefined(lpNTFS_VOLUME_DATA_BUFFER) Then BinaryFree(lpNTFS_VOLUME_DATA_BUFFER)
   If IsDefined(lpReturnedBytes) Then BinaryFree(lpReturnedBytes)
   Message("Error Occured on line",wberrorhandlerline)
   Return 0

#EndFunction

#DefineFunction UDFCvtFloatToHuge(f)
   ;This UDF converts a floating point number to a
   ;high-precision decimal number suitable for use
   ;by the hugemath extender.

   ;normalize number convert the "E" to uppercase just in case
   fupper=StrUpper(f + 0.0)
   ;get stuff in front of the E
   f1=ItemExtract(1,fupper,"E")
   ;get stuff behinf the E
   f2=ItemExtract(2,fupper,"E")
   ;If there is no E just return the number as is
   If f2=="" Then Return(f1)

   ;figure  out if the number is negative or not
   neg=@FALSE
   If f1<0
      ;If the number was negative, remember that fact
      ;and convert it to a positive number
      neg=@TRUE
      f1 = -f1
   EndIf

   ;remove the .  Assume we are dealing with a normal
   ;scientific notation number where it loos like x.xxxxEyyy
   ;with just one digit in fron of the decimal
   f1=StrReplace(f1,".","")   ; remove .

   If f2<0
     ;if exponent (E Number) is negative, add zeros in front

      f1=StrCat("0.",StrFixLeft(f1,0,-(f2)+StrLen(f1)-1))
   Else
      ;exponent is positive.  Add zeros behind
      f1=StrFix(f1,0,Max(StrLen(f1) , f2+1))
   EndIf

   If neg==@FALSE Then Return(f1)
   Else Return (StrCat("-",f1))

#EndFunction




;Get Available Space
DRIVE = 'C:'
VolumeSerialNumber = GET_NTFS_VOLUME_DATA(DRIVE, 0) ;VolumeSerialNumber
Message("VolumeSerialNumber",VolumeSerialNumber)

NumberSectors = GET_NTFS_VOLUME_DATA(DRIVE, 1) ;NumberSectors
Message("NumberSectors",NumberSectors)

TotalClusters = GET_NTFS_VOLUME_DATA(DRIVE, 2) ;TotalClusters
Message("TotalClusters",TotalClusters)

FreeClusters = GET_NTFS_VOLUME_DATA(DRIVE, 3) ;FreeClusters
Message("FreeClusters",FreeClusters)

TotalReserved = GET_NTFS_VOLUME_DATA(DRIVE, 4) ;TotalReserved
Message("TotalReserved",TotalReserved)




Article ID:   W17271
File Created: 2007:07:03:14:29:08
Last Updated: 2007:07:03:14:29:08