GetDiskFreeSpaceEx
GetDiskFreeSpaceEx
(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 ;-)
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.
FreeCOM
Wrong.FreeCOM is a 16-bit program so it can only see the 2GB of storage
All true.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.
16 or 32 ???
NO. FreeDOS (16) supports FAT32 pretty well. Otherwise, my GetDiskFreeSpaceEx routine wouldn't work ;-)Well, actually its a limit of the 16-bit filesystem used by DOS.
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.pretty sure FreeCOM is a 16-bit application though
NO.... unless you're thinking of FreeDOS32.
INT's
MichaelW wrote:
sir_mud wrote:
But it seems that you spread confusion arguing something like "Int21 is obsolete, replaced by Int13" :-(
MichaelW wrote:
------------------------------------------------------------------------------------
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.
Somewhat true. Even more.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 wrote:
NO. There is nothing "seems"-like in my code. It uses INT 21/AX=7303h and it's perfectly obvious.From StopTCPA's posts it seems to be using the older Int21.
But it seems that you spread confusion arguing something like "Int21 is obsolete, replaced by Int13" :-(
MichaelW wrote:
FAT32 instead of FAT16 ? Also, the conditional is missplaced: FreeDOS and EDR-DOS do support FAT32.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.
------------------------------------------------------------------------------------
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.
Re: GetDiskFreeSpaceEx
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?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
is this about ???
It works :-DWhat is this about? Is it related to passing 32-bit DPMI addresses directly to the API int, and assuming
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.not quite sure why you wouldn't just use __dpmi_int and avoid the inline assembly mess and requirement for a special DPMI server.
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 :-)
'' --------------------------------------------------------------------
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 ;-) )
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 wrote:Fixed all issues :-)Code: Select all
REM !!! DOS only !!!