GetDiskFreeSpaceEx

DOS specific questions.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

GetDiskFreeSpaceEx

Post by DOS386 »

(request of Fox in Beginners subforum)

EDIT (2008-07-24) : deleted immature buggy code posted exactly 1 year ago, had a flag(C)-related bug (nobody noticed :-( ), and required HDPMI32 - see below for fixed code, if you have a copy of the code from this post please update ;-)
Last edited by DOS386 on Jul 25, 2008 2:18, edited 2 times in total.
sir_mud
Posts: 1401
Joined: Jul 29, 2006 3:00
Location: US
Contact:

Post by sir_mud »

FreeCOM is a 16-bit program so it can only see the 2GB of storage, it is kind of buggy, but it's still a great program compared to the crappy command.com in ms-dos and its constantly improving. If you think its reporting the wrong value then you should report it as a bug report for FreeCOM.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

FreeCOM

Post by DOS386 »

FreeCOM is a 16-bit program so it can only see the 2GB of storage
Wrong.
it is kind of buggy, but it's still a great program compared to the crappy command.com in ms-dos and its constantly improving. If you think its reporting the wrong value then you should report it as a bug report for FreeCOM.
All true.
sir_mud
Posts: 1401
Joined: Jul 29, 2006 3:00
Location: US
Contact:

Post by sir_mud »

Well, actually its a limit of the 16-bit filesystem used by DOS. I'm pretty sure FreeCOM is a 16-bit application though... unless you're thinking of FreeDOS32.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

16 or 32 ???

Post by DOS386 »

Well, actually its a limit of the 16-bit filesystem used by DOS.
NO. FreeDOS (16) supports FAT32 pretty well. Otherwise, my GetDiskFreeSpaceEx routine wouldn't work ;-)
pretty sure FreeCOM is a 16-bit application though
YES. But it uses the "GetDiskFreeSpaceEx" call Int 21/AX=7303h badly or not at all ... it's FreeCOM's bug. EDR-DOS-COM works well.
... unless you're thinking of FreeDOS32.
NO.
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Post by MichaelW »

With the availability of the Interrupt 13h Extensions, starting around the mid 1990’s IIRC, the BIOS could handle disk drives up to 137GB using 28-bit LBA, so I can see no reason why a nominally 16-bit OS or program should necessarily be limited to 2GB.
sir_mud
Posts: 1401
Joined: Jul 29, 2006 3:00
Location: US
Contact:

Post by sir_mud »

From StopTCPA's posts it seems to be using the older Int21.
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Post by MichaelW »

Int 21/AX=7303h started with the FAT32 versions of Windows 95/DOS 7.x. My point was mainly: why should a recent 16-bit OS implement FAT16 when for a little more effort FAT32 could be implemented, and many/most of the systems currently in use could take advantage of it.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

INT's

Post by DOS386 »

MichaelW wrote:
With the availability of the Interrupt 13h Extensions, starting around the mid 1990’s IIRC, the BIOS could handle disk drives up to 137GB using 28-bit LBA, so I can see no reason why a nominally 16-bit OS or program should necessarily be limited to 2GB.
Somewhat true. Even more.

sir_mud wrote:
From StopTCPA's posts it seems to be using the older Int21.
NO. There is nothing "seems"-like in my code. It uses INT 21/AX=7303h and it's perfectly obvious.

But it seems that you spread confusion arguing something like "Int21 is obsolete, replaced by Int13" :-(

MichaelW wrote:
Int 21/AX=7303h started with the FAT32 versions of Windows 95/DOS 7.x. My point was mainly: why should a recent 16-bit OS implement FAT16 when for a little more effort FAT32 could be implemented, and many/most of the systems currently in use could take advantage of it.
FAT32 instead of FAT16 ? Also, the conditional is missplaced: FreeDOS and EDR-DOS do support FAT32.

------------------------------------------------------------------------------------

INT 13 is a BIOS INT and used for physical disk access.

INT 21 is a DOS INT used for file access and other DOS services.

Both are somewhat very "old" but were enhanced several times and are still perfectly up-to-date.

Latest INT 13 implementations support IDE and SATA HD's , CHS/LBA28/LBA48, up to 2 TiB.

Latest INT 21 supports FAT12, FAT16, FAT32, FAT32+, with VFAT/LFN, and partitions up to 2 TiB and files up to 256 GiB.
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: GetDiskFreeSpaceEx

Post by marcov »

StopTCPA wrote:
Note 2: Code requires a DPMI kernel with "DOS API translation" like
HDPMI32, but does NOT verify this - unpredictable failure will result
with CWSDPMI :-D
What is this about? Is it related to passing 32-bit DPMI addresses directly to the API int, and assuming that they are visible in dos space?
DrV
Site Admin
Posts: 2116
Joined: May 27, 2005 18:39
Location: Midwestern USA
Contact:

Post by DrV »

Yes, I'm not quite sure why you wouldn't just use __dpmi_int and avoid the inline assembly mess and requirement for a special DPMI server.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

is this about ???

Post by DOS386 »

What is this about? Is it related to passing 32-bit DPMI addresses directly to the API int, and assuming
It works :-D
not quite sure why you wouldn't just use __dpmi_int and avoid the inline assembly mess and requirement for a special DPMI server.
My code works and shows one way how to do. Of course, one could include the translation with INT 300 into the code. I personally prefer inline ASM from the "mess" with accessing registers the "pure" C/BASIC way. Also, implementing the address translation and transfer buffer in the "C library" and using a "non-special DPMI server" is a way to do but it is not necessarily the only nor the best one.
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

Post by DOS386 »

Code: Select all

'' --------------------------------------------------------------------

'' ### DOS GetDiskFreeSpaceEx example (R) ###
'' (CL) 2008-07-24 by DOS386 | Public Domain | ABUSE at your own risk !!!
'' "FREE.BAS" , COMPILE WITH FBC 0.20 to DOS target
'' !!! DOS only !!! | Requires a recent DOS kernel (FreeDOS, EDR-DOS, RX-DOS)
'' Uses INT $31/$0300, works with any usable DPMI host (D3X, HDPMI32, ...)

'' --------------------------------------------------------------------

#include "dos/go32.bi" '' DPMI stuff declarations

type UINT64  as ULONGINT
type UINT32  as UINTEGER
type UINT8   as UBYTE

declare sub GDFSEX (BYVAL AS UINT32, BYVAL AS UINT32)
'' Address of src spec string (<=12 chars), address of dest buffer (64 bytes)

DIM SHARED AS UINT32 DDS, LTB

DIM SHARED AS STRING  VGSCOMMAND
DIM SHARED AS UINT64  VGN64FREE, VGN64TOTAL
DIM SHARED AS UINT32  A1, A2, A3, A4, A5
DIM SHARED AS UINT8   INFOBUF (0 TO 64)

'' Init GO32
DDS = _go32_info_block.selector_for_linear_memory
LTB = _go32_info_block.linear_address_of_transfer_buffer

VGSCOMMAND=UCASE$(COMMAND$(1))
IF (VGSCOMMAND<>"\") AND (LEN(VGSCOMMAND)<2) THEN VGSCOMMAND="." 
'' Default drive, "." or "\" (might not work with every DOS)

? : ? "FREE.BAS | FREE.EXE | GetDiskFreeSpaceEx | (CL) 2008-07-24"
? : ? "Usage example: ""FREE D:\"""
? : ? "Looking for total & free space in """+VGSCOMMAND+""" :-D" : ?

A1=CAST(UINT32,STRPTR(VGSCOMMAND)) '' Source spec
A2=CAST(UINT32,VARPTR(INFOBUF(0))) '' Dest buffer

? "Calling the INT ... " ;
GDFSEX (A1,A2)
? "done !!!" : ?

A1 = INFOBUF( 0) + ( INFOBUF( 1) SHL 8 ) '' SUCCESS / SIZE
A2 = INFOBUF( 4) + ( INFOBUF( 5) SHL 8 ) '' SEC/CLU
A3 = INFOBUF( 8) + ( INFOBUF( 9) SHL 8 ) '' BYT/SEC
A4 = INFOBUF(28) + ( INFOBUF(29) SHL 8 ) + _
     ( INFOBUF(30) SHL 16 ) + ( INFOBUF(31) SHL 24 ) '' FREE CLU
A5 = INFOBUF(32) + ( INFOBUF(33) SHL 8 ) + _
     ( INFOBUF(34) SHL 16 ) + ( INFOBUF(35) SHL 24 ) '' TOTAL CLU

? "Results:" : ?

? "Success/Size (>0) : ";A1
? "Sec/Clu (1...64)  : ";A2
? "Byt/Sec (512)     : ";A3
? "Clust free        : ";A4
? "Clust total       : ";A5

IF (A1<>0) THEN

  VGN64FREE  = CAST(UINT64,(A2 * A3))
  VGN64TOTAL = VGN64FREE
  VGN64FREE  = VGN64FREE  * A4
  VGN64TOTAL = VGN64TOTAL * A5

  ? : ? "Bytes free  : " ; VGN64FREE
  If VGN64FREE>&H0400       THEN ? "KiB free    : " ; (VGN64FREE Shr 10)
  If VGN64FREE>&H0100000    THEN ? "MiB free    : " ; (VGN64FREE Shr 20)
  If VGN64FREE>&H040000000  THEN ? "GiB free    : " ; (VGN64FREE Shr 30)

  ? : ? "Bytes total : " ; VGN64TOTAL
  If VGN64TOTAL>&H0400      THEN ? "KiB total   : " ; (VGN64TOTAL Shr 10)
  If VGN64TOTAL>&H0100000   THEN ? "MiB total   : " ; (VGN64TOTAL Shr 20)
  If VGN64TOTAL>&H040000000 THEN ? "GiB total   : " ; (VGN64TOTAL Shr 30)

ENDIF

? : ? "Done !!!" : ?

END

'' --------------------------------------------------------------------

SUB GDFSEX (BYVAL VLN32SPEC AS UINT32, BYVAL VLN32DEST AS UINT32)

'' GetDiskFreeSpaceEx - INT $21/$7303 | src: [DS:DX] | dest:[ES:DI]
''
'' IN:  addr of spec: "C:\" or "." (12 max), addr of buffer (64 bytes)
'' OUT: nothing / buffer filled
''
'' Memory:   0: $32 bytes INT $31  | $32: $0E bytes wasted
''         $40: $10 bytes src spec | $50: $40 bytes dest buffer / struct
''         $90: 1.5 KiB stack
''
'' Uses globals: LTB (linear addr of buffer) and DDS (ZERO-based selector)

  ASM

      mov   edi,[LTB]  '' For clear (2 KiB) and INT (based on ES, size=$32)
      mov   eax,[DDS]
      push  eax
      pop   es         '' !!! Trashing ES
      cld

      xor   eax,eax    '' For DPMI simulant INT $31 and clearing
      xor   ecx,ecx    '' &
      mov   ch,2       '' & MOVNTQ ECX,512
      push  edi
      rep   stosd      '' [ES:EDI] ZERO'izing 2 KiB | side effect: ECX==0
      pop   edi

      push  edi
      add   edi,0x40
      mov   esi,[VLN32SPEC]
      movsd            '' [ES:EDI]<-[DS:ESI] | ESI and EDI trashed
      movsd            
      movsd            '' 12 bytes spec size max
      pop   edi

      mov   ah,3       '' @ For DPMI simulant INT $31 / $0300 see far below
      mov   bl,0x21    '' @ BL=$21 | Don't touch AX and BX below
      mov   bh,0       '' @ BH=0 (crap flags)

      mov  cl,48             '' & Expected size
      mov  [es:edi+0x18],cl  '' & CL / CX / ECX
      mov  ch,0x73           '' % GetDiskFreeSpaceEx
      mov  cl,0x03           '' % GetDiskFreeSpaceEx
      mov  [es:edi+0x1C],ecx '' % EAX / AX = $7303
      mov  ecx,edi           '' @ Linear
      shr  ecx,4             '' @ To segment | high 16 bits==0
      add  ecx,4             '' @ Skip $32 -> $40 bytes | high 16 bits ==0
      mov  [es:edi+0x24],cx  '' @ DS Segment address of spec (OFF***==0)
      inc  ecx               '' @ Now + $50
      mov  [es:edi+0x22],cx  '' @ ES Segment address of buff (OFF***==0)
      add  ecx,4             '' @ Now + $90
      mov  [es:edi+0x30],cx  '' @ SS
      mov  dh,6              '' & 1.5 KiB stack
      mov  [es:edi+0x2F],dh  '' & SP high byte

      pushf
      pop  edx
      mov  [es:edi+0x20],dl  '' FLAGS 16-bit only, we poke only 8-bit

      xor  ecx,ecx           '' MOVNTQ ECX,0
      int  0x31              '' AX==$0300 | BX==$21 see far above

      mov   edi,[LTB]        '' Again ??? Required ???
      mov   eax,[DDS]
      push  eax
      pop   es               '' !!! Trashing ES
      cld

      push  edi
      xor   ecx,ecx          '' MOVNTQ ECX,0 | For clearing and CX / CL high
      mov   bl,[es:edi+0x20] '' FLAGS
      add   edi,0x50         '' !!! now points to result buffer directly !!!     
      shr   bl,1             '' Now we have it in flag (C)
      jc    xx1              '' F**K, didn't work :-(

      mov   cl,[es:edi]    '' Resulting size
      cmp   cl,32          '' Minimum
      jb    xx1            '' Too small, result = :-(
      cmp   cl,63
      ja    xx1            '' Too big, result = :-( as well
      add   edi,ecx        '' Skip good buffer, clearing will run into stack
     
xx1:  xor   eax,eax        '' For clearing, if very angry, clear the result
      mov   cl,0x28        '' MOVNTQ ECX, $28 = #40 | see above for 24 top
      rep   stosd          '' [ES:EDI] clear 160 bytes | side effect: ECX==0
      pop   edi            '' Pope original EDI, not +$50 +blah !!!

      mov   esi,[VLN32DEST] '' & Our destination, but for now in ESI !!!
      xchg  esi,edi         '' & Fix ^^^ it
      add   esi,0x50        '' & Skip DPMI simulant structure + more garbage
      push  ds              '' @ non-ZERO
      push  es              '' @ ZERO | SWAP DS,ES | No "XCHG DS,ES" :-(
      pop   ds              '' @ ZERO
      pop   es              '' @ non-ZERO
      mov   cl,0x10         '' $10 -> $40 bytes | see above about 24 top bits
      rep   movsd           '' [ES:EDI]<-[DS:ESI] | ESI and EDI trashed
      push  es              '' @
      pop   ds              '' @ Crucial !!!

  END ASM

END SUB

'' --------------------------------------------------------------------

'' Int $21/AX=$7303 GetDiskFreeSpaceEx
''
'' FreeDOS, EDR-DOS, RX-DOS (Windoze95) -
'' FAT32 - GET EXTENDED FREE SPACE ON DRIVE
''
'' BEWARE: There is a PATH BUG !!! "C:\" - FreeDOS | "C:" - EDR-DOS
'' Further FreeDOS rejects "." , while EDR-DOS accepts it.
'' BUG: EDR-DOS returns with AL=0 AND CF=0 if "\" is present !!!
'' You should check for success size, not for failure via AL=0 !!!
''
'' AX = $7303
'' DS:DX -> ASCIZ string for drive ("C:\" or "\\SERVER\Share")
'' ES:DI -> buffer for extended free space structure (see #01789)
'' CX = length of buffer for extended free space (can be cca 36...44 bytes)
''
'' Return:
'' CF clear if successful ||| ES:DI buffer filled
'' CF set on error        ||| AX = error code
''
'' Notes: On DOS versions which do not support the FAT32 calls,
'' this function returns CF clear/AL=0 (which is the DOS v1+
'' method for reporting unimplemented functions). Under DOG 7.x
'' (i.e. "MSDOG Mode" under Windoze95), the ASCIZ string pointed
'' at by DS:DX *must* include the drive letter, or this function
'' will return CF set/AX=$15 (invalid drive). In a DOG box,
'' omitting the drive letter (DS:DX -> "\") results in the free
'' space for the current default drive, as expected
''
'' BUG (IRRELEVANT): This function returns a maximum of "2GB" free space
'' even on an FAT32 partition larger than "2GB" under some versions of Win95
'' and Win98, apparently by limiting the number of reported free clusters to
'' no more than "64K" -- but only in a DOG window if a TSR has hooked INT $21
''
'' See Also: AX=$7302 - AX=$7304 - AX=$7305 - AH=$36
''
'' Format of extended free space structure: Offset Size Description
'' (Table 01789)
'' $00 WORD  ret: size of returned structure
'' $02 WORD  call: requested struct version (0) | ret: actual struct version (0)
'' $04 DWORD number of sectors per cluster (with adjustment for compression)
'' $08 DWORD number of bytes per sector
'' $0C DWORD number of available clusters
'' $10 DWORD total number of clusters on the drive
'' $14 DWORD number of physical sectors available on the drive, without adj for compr
'' $18 DWORD total number of physical sectors on the drive, without adj for compr
'' $1C DWORD number of available allocation units, without adj for compr
'' $20 DWORD total allocation units, without adjustment for compression
'' $24 8 BYTE's reserved

'' --------------------------------------------------------------------

'' INT $31 / $0300
'' $00  DWORD   EDI
'' $04  DWORD   ESI
'' $08  DWORD   EBP
'' $0C  DWORD   reserved (0)
'' $10  DWORD   EBX
'' $14  DWORD   EDX
'' $18  DWORD   ECX
'' $1C  DWORD   EAX
'' $20  WORD    flags
'' $22  WORD    ES
'' $24  WORD    DS
'' $26  WORD    FS
'' $28  WORD    GS
'' $2A  WORD    IP
'' $2C  WORD    CS
'' $2E  WORD    SP
'' $30  WORD    SS
'' $32  END :-)

'' --------------------------------------------------------------------
Fixed all issues :-)

Works with D3X, WDOSX, HDPMI32, maybe even CWSDPMI.

Some "external" bugs:

- FreeCOM of FreeDOS reports badly free space > 1 GiB and completely fails to detect > 2 GiB ... 1 year later and still same bug present and no FreeDOS 1.1 :-(

- FreeDOS kernel rejects "." and "\" for default drive in this GetDiskFreeSpaceEx call, as well as "C:" - only "C:\" works

- EDR-DOS now accepts all "." , "\" , "C:" and "C:\" - but it still sets AL=0 on success (bad, OTOH I don't test for AL at all ;-) )
rugxulo
Posts: 219
Joined: Jun 30, 2006 5:31
Location: Usono (aka, USA)
Contact:

Post by rugxulo »

DOS386 wrote:

Code: Select all

REM !!! DOS only !!!
Fixed all issues :-)
I guess ... although Win XP etc. don't support int 21h,7303h natively, you can load the NTLFN thingy and it'll work (at least, DJGPP port of df / du are correct only after loading such). However, that doesn't work with your program. Not a big issue, but just a side-note (although I e-mailed you something about this recently, guess it wasn't high priority, and I don't majorly care either way so ...).
DOS386
Posts: 798
Joined: Jul 02, 2005 20:55

Post by DOS386 »

rugxulo wrote:I e-mailed you something about this recently, guess it wasn't high priority
I did read the mail ... but it "didn't work" :-(
Post Reply