The answer comes in the units of the FAT file system. A sector is the disk's unit of transfer (512 bytes on every PC disk); a cluster is a group of sectors and the smallest piece of disk a file can get, so every file's size on disk is rounded up to whole clusters. 36h returns how big a cluster is and how many there are:
| Quantity | From the registers |
|---|---|
| bytes per cluster | AX × CX |
| free bytes | AX × CX × BX |
| size of the drive | AX × CX × DX |
The products do not fit 16 bits. Two MULs do it: the first gives the cluster size (in AX alone for clusters up to 32 KB), the second multiplies by the free clusters and leaves the free bytes in DX:AX:
MUL CX ; AX = bytes per cluster (DX = 0)MUL BX ; DX:AX = free bytes
Errors are reported the old way, before DOS used the carry flag: AX = FFFFh means the drive does not exist, and nothing else is set. For a floppy drive without a disk, DOS calls the critical error handler first (INT 24h: Not ready reading drive A, Abort, Retry, Fail), and returns FFFFh if the user picks Fail.
The registers are 16 bits, so a drive larger than 2 GB cannot be described. DOS 7.1 caps the numbers here at just under 2 GB and offers function 7303h of INT 21h for the real ones on FAT32.
In DOSBox-X
A drive mounted from a folder on the host has no clusters: DOSBox-X makes up a geometry and reports as free space the amount MOUNT was given with -freesize. In the workbench, C: reports what is left of the box's disk allowance. Z:, DOSBox-X's virtual drive, always reports 32 sectors of 512 bytes per cluster, 32765 clusters and nothing free, so the example asks about Z: and its output is always the same:
MOV DX, OFFSET ZM1MOV AH, 09hINT 21hMOV AH, 36h ; DOS: free space on drive DLMOV DL, 26 ; 26 = Z: (1 = A here; 0 = the current drive)INT 21hCMP AX, 0FFFFh ; FFFFh: no such driveJE NONE1MOV BPS1, CX ; keep the answer: printing changes itMOV FREE1, BXMOV TOTAL1, DXCALL PDEC ; sectors per clusterMOV DX, OFFSET SPCM1MOV AH, 09hINT 21hMOV AX, BPS1CALL PDECMOV DX, OFFSET BPSM1MOV AH, 09hINT 21hMOV AX, FREE1CALL PDECMOV DX, OFFSET OFM1MOV AH, 09hINT 21hMOV AX, TOTAL1CALL PDECMOV DX, OFFSET FREEM1MOV AH, 09hINT 21hNONE1:MOV DX, OFFSET BADM1MOV AH, 09hINT 21hMOV AH, 36h ; a drive that cannot existMOV DL, 27INT 21hCALL PHEX ; FFFFMOV DX, OFFSET CRLFMOV AH, 09hINT 21hZM1 DB "Z: $"SPCM1 DB " sectors x $"BPSM1 DB " bytes, $"OFM1 DB " of $"FREEM1 DB " clusters free", 13, 10, "$"BADM1 DB "drive 27: AX = $"BPS1 DW 0FREE1 DW 0TOTAL1 DW 0CRLF DB 13, 10, "$"PDEC PROC NEAR ; print AX in decimal (changes AX BX CX DX)MOV BX, 10XOR CX, CX ; digits on the stackPDEC1:XOR DX, DXDIV BX ; AX = AX / 10, DX = the last digitPUSH DXINC CXOR AX, AXJNZ PDEC1PDEC2:POP DX ; the digits come back first to lastADD DL, "0"MOV AH, 02hINT 21hLOOP PDEC2RETPDEC ENDPPHEX PROC NEAR ; print AX as four hex digits (changes AX BX CX DX)MOV BX, AXMOV CX, 4PHEX1:PUSH CXMOV CL, 4ROL BX, CL ; the top digit to the bottomPOP CXMOV DL, BLAND DL, 0FhADD DL, "0"CMP DL, "9"JBE PHEX2ADD DL, 7 ; "A" to "F"PHEX2:MOV AH, 02hINT 21hLOOP PHEX1RETPHEX ENDP
INT 21h AH=1Ch returns the same geometry without the free count (and INT 21h AH=1Bh for the current drive), plus a pointer to the media descriptor byte.