Skip to content

Commit 3e28a72

Browse files
committed
use extended disk free space API to better handle checking for enough room for files larger than 2GB, fixes issue #4
1 parent 4106cda commit 3e28a72

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

src/misc.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <stdio.h>
2+
#include <ctype.h> /* for toupper */
23

34
#ifdef __GNUC__
45
#include <direct.h>
@@ -313,3 +314,89 @@ int copy_file(const char *src_filename,
313314

314315
return 1;
315316
}
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+
}

src/misc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ extern char *strmcpy(char *dest, const char *src, const unsigned int maxlen);
6060
extern char *strmcat(char *dest, const char *src, const unsigned int maxlen);
6161
extern int copy_file(const char *src_filename, const char *dest_filename);
6262
extern void build_filename(char *, const char *, const char *);
63+
extern unsigned long getdiskfreespace(unsigned drive, int *error);
6364

6465
#define error(x,y,msg) PRINTF(" [%s]\n", catgets(cat,x,y,msg))
6566

src/move.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,6 @@ static void move_files(const char *src_pathname, const char *src_filename,
386386
static void prepare_move(char *src_filename, char *dest_filename)
387387
{
388388
struct stat src_statbuf;
389-
struct dfree disktable;
390389
unsigned long free_diskspace;
391390
char buf[2 + 4 + 1]; /* 2 byte overhead + strlen + nul */
392391
char *input;
@@ -474,8 +473,7 @@ static void prepare_move(char *src_filename, char *dest_filename)
474473
stat((char *)src_filename, &src_statbuf);
475474

476475
/* Get amount of free disk space in destination drive. */
477-
getdfree(dest_drive, &disktable);
478-
free_diskspace=(unsigned long) disktable.df_avail * disktable.df_sclus * disktable.df_bsec;
476+
free_diskspace=getdiskfreespace(dest_drive, NULL);
479477

480478
/* Check free space on destination disk. */
481479
if (src_statbuf.st_size>free_diskspace)

0 commit comments

Comments
 (0)