|
1 | 1 | #include <stdio.h> |
| 2 | +#include <ctype.h> /* for toupper */ |
2 | 3 |
|
3 | 4 | #ifdef __GNUC__ |
4 | 5 | #include <direct.h> |
@@ -313,3 +314,89 @@ int copy_file(const char *src_filename, |
313 | 314 |
|
314 | 315 | return 1; |
315 | 316 | } |
| 317 | + |
| 318 | + |
| 319 | +unsigned long old_dos_getdiskfree(unsigned drive, int *error) |
| 320 | +{ |
| 321 | + struct dfree disktable; |
| 322 | + unsigned success; |
| 323 | + success = getdfree(drive, &disktable); |
| 324 | + if (error != NULL) *error = success; /* 0=success */ |
| 325 | + return (unsigned long) disktable.df_avail * disktable.df_sclus * disktable.df_bsec; |
| 326 | +} |
| 327 | + |
| 328 | +/* drive 1=A,2=B,3=C,... error can be NULL if don't care */ |
| 329 | +unsigned long extended_dos_getdiskfree(unsigned drive, int *error) |
| 330 | +{ |
| 331 | + static char rootname[] = "C:\\"; |
| 332 | + static union REGS r; |
| 333 | + static struct SREGS s; |
| 334 | + static struct { |
| 335 | + unsigned short whatever; |
| 336 | + unsigned short version; |
| 337 | + unsigned long sectors_per_cluster; |
| 338 | + unsigned long bytes_per_sector; |
| 339 | + unsigned long free_clusters; |
| 340 | + unsigned long total_clusters; |
| 341 | + unsigned long available_physical_sectors; |
| 342 | + unsigned long total_physical_sectors; |
| 343 | + unsigned long free_allocation_units; |
| 344 | + unsigned long total_allocation_units; |
| 345 | + unsigned char reserved[8]; |
| 346 | + } FAT32_Free_Space; |
| 347 | + static unsigned long clustersize; |
| 348 | + |
| 349 | + if (!drive) _dos_getdrive(&drive); /* use current drive */ |
| 350 | + /* Note: RBIL carry clear and al==0 also means unimplemented |
| 351 | + alternately carry set and ax==undefined (usually unchanged) for unimplemented |
| 352 | + ecm: RBIL is wrong, CF unchanged al=0 is the typical error return. |
| 353 | + EDR-DOS returns NC ax=0 so checking for al!=0 here was wrong. |
| 354 | + */ |
| 355 | + rootname[0] = 'A' + drive - 1; |
| 356 | + /* printf("Looking at drive [%s]\n", rootname); */ |
| 357 | + r.w.cflag = 1; /* CY before 21.73 calls! */ |
| 358 | + r.w.ax = 0x7303; |
| 359 | + s.ds = FP_SEG(rootname); |
| 360 | + r.w.dx = FP_OFF(rootname); |
| 361 | + s.es = FP_SEG(&FAT32_Free_Space); |
| 362 | + r.w.di = FP_OFF(&FAT32_Free_Space); |
| 363 | + r.w.cx = sizeof(FAT32_Free_Space); |
| 364 | + intdosx( &r, &r, &s ); |
| 365 | + |
| 366 | + /* see if call supported, if not then fallback to older get disk free API call */ |
| 367 | + if (!(r.w.cflag & 0x01) && (r.h.al)) |
| 368 | + { |
| 369 | + /* calculate free space, but handle some overflow cases (or switch to 64bit values) */ |
| 370 | + clustersize = FAT32_Free_Space.sectors_per_cluster * FAT32_Free_Space.bytes_per_sector; |
| 371 | + /* printf("clustersize=%lu, free_clusters=%lu\n", clustersize, FAT32_Free_Space.free_clusters); */ |
| 372 | + |
| 373 | + /* total free is cluster size * # of free clusters */ |
| 374 | + if (clustersize) |
| 375 | + { |
| 376 | + /* if (MAX_ULONG / operand1) < operand2 then will overflow (operand1 * operand2 > MAX_ULONG */ |
| 377 | + /* printf("Is %lu > %lu?\n", (4294967295ul / clustersize), FAT32_Free_Space.free_clusters); */ |
| 378 | + if ((4294967295ul / clustersize) < FAT32_Free_Space.free_clusters) { |
| 379 | + /* printf("returning max uLONG %lu\n", (unsigned long)-1l); */ |
| 380 | + return (unsigned long)-1; /* max size */ |
| 381 | + } else { |
| 382 | + /* printf("returning %lu\n", clustersize * FAT32_Free_Space.free_clusters); */ |
| 383 | + return clustersize * FAT32_Free_Space.free_clusters; |
| 384 | + } |
| 385 | + } |
| 386 | + } |
| 387 | + /* else ((r.w.cflag & 0x01) || (!r.h.al)) */ |
| 388 | + return old_dos_getdiskfree(drive, error); |
| 389 | +} |
| 390 | + |
| 391 | +/*-------------------------------------------------------------------------*/ |
| 392 | +/* Returns bytes free on disk, up to 4GB */ |
| 393 | +/* If error is not NULL sets to 0 on sucess or nonzero if error */ |
| 394 | +/*-------------------------------------------------------------------------*/ |
| 395 | +unsigned long getdiskfreespace(unsigned drive, int *error) |
| 396 | +{ |
| 397 | + unsigned long freespace; |
| 398 | + if (error != NULL) *error = 0; |
| 399 | + freespace = extended_dos_getdiskfree(drive, error); |
| 400 | + /* printf("FreeSpace is %lu bytes\n", freespace); */ |
| 401 | + return freespace; |
| 402 | +} |
0 commit comments