DOS386
Joined: 08 Dec 2006
Posts: 1905
|
;
; DOS "GetDiskFreeSpaceEx" INT $21/$7303 test
; (CL) Copyleft 2008-01-13 Public Domain - ABUSE at YOUR own risk !!!
; http://board.flatassembler.net/topic.php?t=8139
; Compile with FASM
; Results in .COM of 1067 bytes (sorry, not even 1 GibiByte filled )
;
; Usage:
;
; GDFSEX drive [C] optional "C" will set Carry flag before call
; GDFSEX C:
; GDFSEX C:\ C
;
; !!! 80386 Required !!!
;
; INT $21 / $7303 "GetDiskFreeSpaceEx"
; FreeDOS,EDR-DOS - FAT32 - GET EXTENDED FREE SPACE ON DRIVE
; Call: AX = $7303
; DS:DX -> ASCIZ string for drive ("C:\" or "\\SERVER\Share")
; ES:DI -> buffer for extended free space structure
; CX = length of buffer for extended free space
; Return: CF clear if successful
; ES:DI buffer filled
; CF set on error
; AX = error code
;
; 00 WORD (ret) size of returned structure
; 02 WORD (call) structure version (0)
; (ret) actual structure version (0)
;
; 04 DWORD sectors per cluster
; 08 DWORD bytes per sector
;
; 0C DWORD free clusters
; 10 DWORD total clusters
; 14 DWORD free sectors phys
; 18 DWORD total sectors phys
; 1C DWORD free clusters "alloc"
; 20 DWORD total clusters "alloc"
;
; ToDo/Bugs:
; - Remove messy vars from code
; - Decimal > 4 GiB
format binary as "COM"
use16
org $0100
;[8086]
push cs
pop es
mov dx,tx1
call ssdxprint ; Welcome message
jmp @f
;----------
tx1: db 3,'DOS "GetDiskFreeSpaceEx" INT $21/$7303 test',3
db '(CL) 2008-01-13 Public Domain - ABUSE at YOUR own risk !!',3
db 'Syntax: GDFSEX drive [C]',2
xdrive: db 8 dup (0)
xbuff: db 64 dup (0)
xcf: db 0
xax: db 0,0
xeax: db 0,0,0,0
@@: mov ah,[$80]
cmp ah,3 ; !!! cmd string length + 1
jb qq2 ; <3, no drive, default to current, and no "C" flag
mov cl,7 ; Max lenght
mov si,$82
mov di,xdrive
@@: lodsb ; Pick
cmp al,32
jbe qq3 ; End
stosb
dec cl
jnz @b ; Loop until 7 chars or bad char
qq3: lodsb ; "C" flag ?
cmp al,67
jne qq1 ; NO
inc byte [xcf] ; YES
jmp short qq1
;--------------------
qq2: mov ah,$19 ; DOS 1+ - GET CURRENT DEFAULT DRIVE
int $21 ; Return: AL = drive (0 = A: , 1 = B: , etc)
add al,65
mov ah,58
mov [xdrive],ax
qq1: mov dx,tx2
call ssdxprint
mov dx,xdrive
call ssdxprint
mov al,124
call sscharout
call sseol
mov dx,tx3
call ssdxprint
mov al,[xcf]
add al,48
call sscharout
call ssdeol
jmp @f
;-------------
tx2: db 'Checking drive: |',0
tx3: db 'Calling INT $21 with AX=$7303 and flag(C)=',0
@@: mov ax,$7303
mov cx,48
mov dx,xdrive
mov di,xbuff
mov bl,[xcf]
add bl,255
int $21 ; !!! HOT !!!
mov bl,0
adc bl,0
mov [xcf],bl
mov [xax],ax
mov al,[xbuff]
cmp al,49
jae qiq3 ; Faulty, we asked for 48 bytes only
cmp al,36 ; Minimum
jae qiq4 ; Good
qiq3: mov byte [xbuff],0 ; Bad
qiq4: mov dx,tx4
call ssdxprint
mov al,[xcf]
add al,48
call sscharout ; Flag(C)
call sseol
mov dx,tx5
call ssdxprint
mov ax,[xax]
call sshexd16 ; AX
mov dx,tx6
call ssdxprint
cmp byte [xbuff],0
jne @f ; GOOD
mov dx,tx7
call ssdxprint
@@: mov dx,tx8
call ssdxprint
jmp @f
;-------------
tx4: db 'Results:',3
db 'Flag(C)=',0
tx5: db 'AX=',0
tx6: db 3,'Buffer ',0
tx7: db 'NOT ',0
tx8: db 'filled',2
@@: cmp byte [xcf],0
je @f ; Flag(C)=0
mov dx,tx11
call ssdxprint ; Call failed
jmp qq5 ; Done
;--------------
@@: cmp byte [xbuff],0
jne @f ; GOOD, we had success
mov dx,tx10
call ssdxprint ; Unsupported
jmp qq5 ; Done
;--------------
@@: mov dx,tx12
call ssdxprint ; 9 x desc
;[80386]
xor ecx,ecx
@@: mov eax,[xbuff+ecx]
push ecx
push ax
shr eax,16
call sshexd16
call ssapo
pop ax
call sshex16
mov al,32
call sscharout
pop ecx
add ecx,4
cmp ecx,36
jne @b
call ssdeol
mov dx,tx9
call ssdxprint ; Free
mov eax,[xbuff+4] ; s/c
mov ebx,[xbuff+8] ; b/s
mul ebx
test edx,edx
jz @f ; Must be 0, otherwise >= 4 GiB cluster !!!
xor eax,eax
@@: mov ebx,[xbuff+$0C] ; Free clusters
mul ebx ; Now we have final result in EDX:EAX
mov [xeax],eax ; Save lower 32 bits it here
test edx,edx
jz @f ; < 4 GiB, also dec result
mov ax,dx ; Would work up to 2^48 bytes = 16 TiB
call sshexd16 ; Here we get full result but only in HEX, no dec
call ssapo
mov ax,[xeax+2]
call sshex16
call ssapo
mov ax,[xeax]
call sshex16
jmp qq5 ; Done
;--------------
@@: mov ax,[xeax+2]
call sshexd16
call ssapo
mov ax,[xeax]
call sshex16
mov al,32
call sscharout
mov eax,[xeax]
call ssdec32
qq5: call ssdeol
mov ax,$4C00
int $21
;--------------
tx9: db 'Free: ',0
tx10: db 'This faulty DOS/DOG seems not to support "GetDiskFreeSpaceEx" ',0
tx11: db 'Call failed, drive does not exist ',0
tx12: db 'ver...size ..sec/clus bytes/sect '
db 'free.clust total.clus free.sects total.secs free.clust total.clus',1
; SUB Write HEXD16 | input in AX | trashes all | pritns "$" also
sshexd16:
push ax
mov al,36
call sscharout
pop ax
; pass
; SUB Write HEX16 | input in AX | trashes all
sshex16: mov cl,4
qq6: mov dl,ah ; DL <- AH
shl ax,4
shr dl,4
add dl,$30
cmp dl,$3A
jb @f ; "b" : below unsigned | OK, a number
add dl,7
@@: push ax
push cx
mov al,dl
call sscharout
pop cx
pop ax
dec cl
jnz qq6
ret
;-----------
ssapo: mov al,39
jmp short sscharout
;---------------------------
ssdeol: call sseol
; pass
sseol: mov al,13
call sscharout
mov al,10
; pass
sscharout: push ax ; In: AL
push bx
push dx
cmp al,10
jb @f ; Skip crap "characters"
mov ah,2
mov dl,al
int $21
@@: pop dx
pop bx
pop ax
ret
;-------------
ssdxprint:
push ax ; IN: DX ||| ASCIIZ: 0 instead of "$" !!!
push bx ; 0:END 1:EOL+END 2:DEOL+END 3:EOL
push dx
mov bx,dx
llprlop:
mov al,[bx]
cmp al,0
jz qq7
cmp al,1
jnz @f
call sseol
jmp short qq7
;-----------------------
@@: cmp al,2
jnz @f
call ssdeol
jmp short qq7
;-----------------------
@@: cmp al,3
jnz @f
call sseol
mov al,0
@@: call sscharout
inc bx
jmp short llprlop
;---------------------------
qq7: pop dx
pop bx
pop ax
ret
;-----------
; EXDEC.ASM written by MAD for use with the Assembly Tutorial Chapter 4
; Upgraded to 32 bits In : EAX
; Converts a number in EAX to decimal format and outputs it to the screen
ssdec32:
mov cl,0 ; POP counter - preset to 0
mov ebx,10 ; Divisor: divide by 10
deciloop:
xor edx,edx ; High 32 bits zero.
div ebx ; Remainder in EDX, quotient in EAX
inc cl ; Increase POP counter
push dx ; And PUSH , no BYTE PUSH exists
test eax,eax ; Is quotient zero?
jnz deciloop ; If not, get one more number
popeloop:
pop ax ; Get number
add al,48 ; Add ASCII base (48="0")
call sscharout
dec cx
jnz popeloop
ret
;------
;END.
Download now : http://board.flatassembler.net/download.php?id=3529 ( 7 KiB )
Enjoy
The goal of this code is, besides providing an example of DOS development with FASM, testing bugs in DOS kernels.
Following bugs or non-optimal behavior occurs:
FreeDOS
- Call fails if no slash in drive string: "C:\" works, "C:" fails. EDR-DOS doesn't have this bug.
EDR-DOS
- Call returns with AX=0 and thus AL=0. According to (moronious) last "official" version of RBIL from 2000, "AL=0 and flag(C)=0" is the evidence of non-supported call. According to Udo (not registered here (yet)), his implementation is 100% correct (maybe he is somewhat right - I don't have the final evidence of opposite, because of AH=0 also), and it's 100% safe (here I have to oppose, it's NOT safe, because of (moronious) RBIL at least). Fix is easy - just set AL to 1 (or any other non-ZERO value before returning.  FreeDOS doesn't have this problem.
- Call does not fail if drive string is garbage, it uses default drive. FreeDOS doesn't have this problem, it correctly fails. Both do correctly fail on a valid-looking non-existent drive like "P:\" if you have no "P". Fix: accept "\" and maybe "." as default drive, "C:" or "C:\" or any other letter to test a given drive, but fail otherwise.
_________________ Bug Nr.: 12345
Title: Hello World program compiles to 100 KB !!!
Status: Closed: NOT a Bug
|