From: Martin Str|mberg Message-Id: <199911061418.PAA25968@father.ludd.luth.se> Subject: statfs patch (a little FAT32) To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS) Date: Sat, 6 Nov 1999 15:18:03 +0100 (MET) X-Mailer: ELM [version 2.4ME+ PL15 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com Please consider this patch that makes statfs() report the correct used and free amount of space on disks bigger than 2GiB (this is the FAT32 connection). It's very local and does not mess with important syscalls (like open()). U2, The Unforgettable Fire, MartinS --- v:/djgpp/djgpp/src/libc/compat/sys/vfs/statfs.c Wed Aug 4 21:58:22 1999 +++ src/libc/compat/sys/vfs/statfs.c Sat Mar 13 23:35:08 1999 @@ -1,17 +1,17 @@ -/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ -/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include #include +#include #include #include #include #include #include #include +#include int statfs(const char *path, struct statfs *buf) @@ -19,7 +19,9 @@ __dpmi_regs regs; int drive_number; int cdrom_calls_used = 0; - int blocks = 0; + long blocks = 0; + long free = 0; + long bsize = 0; /* Get the drive number, including the case of magic names like /dev/c/foo. */ @@ -46,7 +48,7 @@ if ((regs.x.flags & 1) == 0 && regs.x.bx == 0xadad && regs.x.ax != 0) { unsigned char request_header[0x14]; - int status, i = 2, bsize = 0; + int status, i = 2; /* Construct the request header for the CD-ROM device driver. */ memset (request_header, 0, sizeof request_header); @@ -91,9 +93,8 @@ if (_farpeekw (_dos_ds, __tb + 8) == 0x100 && _farpeekw (_dos_ds, __tb + 5 + 0x12) == 5) { - regs.x.ax = 1; /* fake: sectors per cluster */ - regs.x.cx = bsize; - regs.x.bx = 0; /* no free space: cannot add data to CD-ROM */ + /* bsize has been set some lines above. */ + free = 0; /* no free space: cannot add data to CD-ROM */ blocks = _farpeekl (_dos_ds, __tb + 1); cdrom_calls_used = 1; } @@ -102,26 +103,84 @@ if (!cdrom_calls_used) { - /* Get free space info from DOS. */ - regs.h.ah = 0x36; /* DOS Get Free Disk Space call */ - regs.h.dl = drive_number + 1; - __dpmi_int(0x21, ®s); + /* Get free space info from DOS. */ + regs.h.ah = 0x36; /* DOS Get Free Disk Space call */ + regs.h.dl = drive_number + 1; + __dpmi_int(0x21, ®s); - /* Check for errors */ - if ((regs.x.ax & 0xffff) == 0xffff) + /* Check for errors */ + if ((regs.x.ax & 0xffff) == 0xffff) + { + errno = ENODEV; + return -1; + } + bsize = regs.x.cx * regs.x.ax; + free = regs.x.bx; + blocks = regs.x.dx; +#if 0 + printf("First: bsize = %ld, free = %ld, blocks = %ld.\n" + , bsize + , free + , blocks + ); +#endif + + if( 7 <= (_get_dos_version(1) >> 8) /* Is FAT32 supported? */ + && _is_fat32(drive_number + 1) /* Is it a FAT32 drive? */ + ) { - errno = ENODEV; - return -1; + /* Get free space info from Extended Drive Parameter Block. */ + regs.x.ax = 0x7302; + regs.h.dl = drive_number + 1; + regs.x.es = __tb_segment; + regs.x.di = __tb_offset; + regs.x.cx = 0x100; /* 256 bytes should be enough (RBIL says 0x3f). */ + __dpmi_int(0x21, ®s); + + /* Errors? */ + if( regs.x.flags & 1 ) + { + errno = ENODEV; + return( -1 ); + } + + /* We trust previous int21 call more if free hasn't maxed out. */ + if( free < blocks ) + { + /* Previous bsize is a multiple of this bsize, so the multiplication + and division here is really a rescaling of the previous free + value. */ + free *= bsize; + bsize = _farpeekw (_dos_ds, __tb + 0x2 + 0x2) * + ( _farpeekb (_dos_ds, __tb + 0x2 + 0x4) + 1 ); + free /= bsize; + } + else + { + free = _farpeekw (_dos_ds, __tb + 0x2 + 0x1f) + + 65536 * _farpeekw (_dos_ds, __tb + 0x2 + 0x21); + bsize = _farpeekw (_dos_ds, __tb + 0x2 + 0x2) * + ( _farpeekb (_dos_ds, __tb + 0x2 + 0x4) + 1 ); + } + + blocks = _farpeekl( _dos_ds, __tb + 0x2 + 0x2d); +#if 0 + printf("Second: bsize = %ld, free = %ld, blocks = %ld.\n" + , bsize + , free + , blocks + ); +#endif + } - blocks = regs.x.dx; } /* Fill in the structure */ - buf->f_bavail = regs.x.bx; - buf->f_bfree = regs.x.bx; + buf->f_bavail = free; + buf->f_bfree = free; buf->f_blocks = blocks; - buf->f_bsize = regs.x.cx * regs.x.ax; - buf->f_ffree = regs.x.bx; + buf->f_bsize = bsize; + buf->f_ffree = free; buf->f_files = blocks; buf->f_type = 0; buf->f_fsid[0] = drive_number;