Message-Id: <5.0.2.1.0.20010107121357.00aa6580@pop5.banet.net> X-Sender: usbanet DOT farley3 AT pop5 DOT banet DOT net (Unverified) X-Mailer: QUALCOMM Windows Eudora Version 5.0.2 Date: Sun, 07 Jan 2001 13:34:54 -0500 To: djgpp-workers AT delorie DOT com From: "Peter J. Farley III" Subject: Re: Fw: Patch for statfs.c Cc: Martin Str|mberg , ceo AT nbensacomputers DOT com In-Reply-To: <200101070649.HAA22174@father.ludd.luth.se> References: <5 DOT 0 DOT 2 DOT 1 DOT 0 DOT 20010107003654 DOT 00aa44f0 AT pop5 DOT banet DOT net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=====================_7574008==_" Reply-To: djgpp-workers AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk --=====================_7574008==_ Content-Type: text/plain; charset="us-ascii"; format=flowed At 07:49 AM 1/7/01 +0100, Martin Str|mberg wrote: >Thanks! Meanwhile I've come up with a new version that reports the >right values with regard to bsize on CDROMs and correct values on >DVDROM as well. Sorry, Martin. This version does not report CD size correctly on my system. Here are the results I got, after rebuilding libc with your new statfs and rebuilding fileutils 3.16 after that. Again, Y: is a DVD-ROM, Z: is a CDRW, same discs loaded as in my prior test. Note that the rebuilt df reports too many 1024 blocks, 326552*1024 = 334389248 while 325888*1024 = 333709312. The difference is 664 blocks, which I cannot explain easily. O:\gnu\filutil3.16\src>.\df z: Filesystem 1024-blocks Used Available Capacity Mounted on Corel Linux 1.2 Sources 326552 326552 0 100% z:/ O:\gnu\filutil3.16\src>\bin\df z: Filesystem 1024-blocks Used Available Capacity Mounted on Corel Linux 1.2 Sources 325888 325888 0 100% z:/ O:\gnu\filutil3.16\src>\bin\df y: Filesystem 1024-blocks Used Available Capacity Mounted on EXCALIBUR_16X9_FF_NA 2097120 2097120 0 100% y:/ O:\gnu\filutil3.16\src>.\df y: Filesystem 1024-blocks Used Available Capacity Mounted on EXCALIBUR_16X9_FF_NA 6729942 6729942 0 100% y:/ O:\gnu\filutil3.16\src>dir /v y: Volume in drive Y is EXCALIBUR_1 Volume Serial Number is AFF1-C159 Directory of Y:\ File Name Size Allocated Modified Accessed Attrib VIDEO_TS 07-22-99 5:58p 07-22-99 R DA VIDEO_TS 0 file(s) 0 bytes 1 dir(s) 0.00 MB free 6,572.21 MB total disk space, 100% in use O:\gnu\filutil3.16\src>dir /v z: Volume in drive Z is Corel Linux Volume Serial Number is 1511-7CA3 Directory of Z:\ File Name Size Allocated Modified Accessed Attrib CORELLIN 2 07-13-00 5:55p D CORELLINUX-1.2 VOLINFO TXT 333 07-13-00 5:55p R VOLINFO.TXT 1 file(s) 333 bytes 1 dir(s) 0 bytes free 333,709,312 bytes total disk space, 100% in use I added some "#if TEST" print statements to produce more detailed info. It sure looks to me like AX1510 is producing wrong results for the CDRW drive and AX7303 is producing correct results. By checking whether AX1510 is greater than AX7303, Martin's code produces (I think) the wrong results for CD's, though correct for DVD's. At least, it produces results that are different from the Win98 "Properties" value. Here are my results (patched statfs.c follows at the end). O:\src\libc\compat\sys\vfs>gcc -O2 -g -DTEST statfs.c -o statfs.exe O:\src\libc\compat\sys\vfs>statfs y:. After AX1510: bsize = 2048, free = 0, blocks = 1147650. After AX7303: bsize = 2048, free = 0, blocks = 3364971. After AX7303+DVD chk: bsize = 2048, free = 0, blocks = 3364971. Results for `y:.': Total blocks: 3364971 Available blocks: 0 Block size: 2048 O:\src\libc\compat\sys\vfs>statfs z:. After AX1510: bsize = 2048, free = 0, blocks = 163276. After AX7303: bsize = 32768, free = 0, blocks = 10184. After AX7303+DVD chk: bsize = 2048, free = 0, blocks = 163276. Results for `z:.': Total blocks: 163276 Available blocks: 0 Block size: 2048 statfs.c with extra print statements follows. HTH --=====================_7574008==_ Content-Type: text/plain; charset="us-ascii" /* 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 #if TEST #include #endif /* Returns: 1 == OK, successful setting of variables. 0 == no cdrom found, variables unchanged. */ static int use_AX0x1510( int drive_number, long *blocks, long *free, long *bsize ) { __dpmi_regs regs; /* For a CD-ROM drive, Int 21h/AX=3600h gives incorrect info. Use CD-ROM-specific calls if they are available. Int 2Fh/AX=1510h gives us a way of doing IOCTL with the CD-ROM device driver without knowing the name of the device (which is defined by the CONFIG.SYS line that installs the driver and can therefore be arbitrary). */ regs.x.ax = 0x150b; /* is this drive supported by CD-ROM driver? */ regs.x.cx = drive_number; __dpmi_int(0x2f, ®s); if ((regs.x.flags & 1) == 0 && regs.x.bx == 0xadad && regs.x.ax != 0) { unsigned char request_header[0x14]; int status, i = 2; /* Construct the request header for the CD-ROM device driver. */ memset (request_header, 0, sizeof request_header); request_header[0] = sizeof request_header; request_header[2] = 3; /* IOCTL READ command */ *(unsigned short *)&request_header[0xe] = __tb_offset; *(unsigned short *)&request_header[0x10] = __tb_segment; request_header[0x12] = 4; /* number of bytes to transfer */ /* When the disk was just changed, we need to try twice. */ do { /* Put control block into the transfer buffer. */ _farpokeb (_dos_ds, __tb, 7); /* read sector size */ _farpokeb (_dos_ds, __tb + 1, 0); /* cooked mode */ _farpokew (_dos_ds, __tb + 2, 0); /* zero out the result field */ /* Put request header into the transfer buffer and call the driver. */ dosmemput (request_header, sizeof (request_header), __tb + 4); regs.x.ax = 0x1510; regs.x.cx = drive_number; regs.x.es = __tb_segment; regs.x.bx = __tb_offset + 4; __dpmi_int (0x2f, ®s); status = _farpeekw (_dos_ds, __tb + 7); *bsize = _farpeekw (_dos_ds, __tb + 2); } while (--i && (status & 0x800f) == 0x800f); /* disk changed */ if (status == 0x100 && _farpeekw (_dos_ds, __tb + 4 + 0x12) == 4) { request_header[0x12] = 5; /* number of bytes to transfer */ /* Put control block into the transfer buffer. */ _farpokeb (_dos_ds, __tb, 8); /* read volume size */ _farpokel (_dos_ds, __tb + 1, 0); /* zero out the result field */ /* Put request header into the transfer buffer and call the driver. */ dosmemput (request_header, sizeof (request_header), __tb + 5); regs.x.ax = 0x1510; regs.x.cx = drive_number; regs.x.es = __tb_segment; regs.x.bx = __tb_offset + 5; __dpmi_int (0x2f, ®s); if (_farpeekw (_dos_ds, __tb + 8) == 0x100 && _farpeekw (_dos_ds, __tb + 5 + 0x12) == 5) { /* bsize has been set some lines above. */ *free = 0; /* no free space: cannot add data to CD-ROM */ *blocks = _farpeekl (_dos_ds, __tb + 1); return 1; } } } return 0; } /* Returns: 0 == OK, successful setting of variables. -1 == call failed, errno set. */ static int use_AH0x36( int drive_number, long *blocks, long *free, long *bsize ) { __dpmi_regs regs; /* 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) { errno = ENODEV; return -1; } *bsize = regs.x.cx * regs.x.ax; *free = regs.x.bx; *blocks = regs.x.dx; return 0; } int statfs(const char *path, struct statfs *buf) { __dpmi_regs regs; int cdrom_calls_used = 0; int drive_number; long blocks = 0; long free = 0; long bsize = 0; /* Get the drive number, including the case of magic names like /dev/c/foo. */ _put_path(path); drive_number = (_farpeekb(_dos_ds, __tb) & 0x1f) - 1; if (_farpeekb(_dos_ds, __tb + 1) != ':' || drive_number == -1) { regs.h.ah = 0x19; __dpmi_int(0x21, ®s); drive_number = regs.h.al; } /* Try cdrom call first. */ cdrom_calls_used = use_AX0x1510( drive_number, &blocks, &free, &bsize ); #if TEST printf("After AX1510: bsize = %ld, free = %ld, blocks = %ld.\n" , bsize , free , blocks ); #endif if( 7 <= _osmajor && _osmajor < 10 ) /* Are INT21 AX=7303 and/or INT21 AX=7302 supported? */ { /* INT21 AX=7303 - Win9x - Get Extended Free Drive Space: INT21 AX=7302, Extended Drive Paramenter Block, seems to report the largest block of free clusters when running under Windows (this info is not confirmed), so I'm using this service here. It expects a path on DS:DX and it should not be an empty string or the sevice call will fail */ if (path && !*path) { _put_path ("/"); } else { _put_path (path); } regs.x.ax = 0x7303; regs.x.ds = regs.x.es = __tb_segment; regs.x.dx = regs.x.di = __tb_offset; regs.x.cx = 0x100; /* Buffer length. Actually ~70 bytes would be enough */ __dpmi_int (0x21, ®s); /* In case INT21 AX=7303 fails we try INT21 AX=7302 (the best we can do). */ if (regs.x.flags & 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 ) { /* If INT21 AX=7302 fails too, we revert to the old code. */ if( ! cdrom_calls_used ) { /* If the earlier call to useAX0x1510() failed we must use INT21 AH=63. */ if( use_AH0x36( drive_number, &blocks, &free, &bsize ) == -1 ) { /* use_AH0x36() sets errno on failure. */ return -1; } #if TEST printf("After AH0x36: bsize = %ld, free = %ld, blocks = %ld.\n" , bsize , free , blocks ); #endif } else { /* Values untouched since the call to useAX0x1510(). */ } } else { free = _farpeekl (_dos_ds, __tb + 0x2 + 0x1f); bsize = _farpeekw (_dos_ds, __tb + 0x2 + 0x2) * ( _farpeekb (_dos_ds, __tb + 0x2 + 0x4) + 1 ); /* -1, because this function was reporting 1 more cluster than CHKDSK. */ blocks = _farpeekl( _dos_ds, __tb + 0x2 + 0x2d) - 1; #if TEST printf("After AX7302: bsize = %ld, free = %ld, blocks = %ld.\n" , bsize , free , blocks ); #endif } } else /* Use information from service AX=0x7303. */ { /* Save values from INT21 AH=0x1510 call. */ long cd_blocks = blocks; long cd_free = free; long cd_bsize = bsize; free = _farpeekl (_dos_ds, __tb + 0x0c); bsize = _farpeekl (_dos_ds, __tb + 0x08) * _farpeekl (_dos_ds, __tb + 0x04); blocks = _farpeekl (_dos_ds, __tb + 0x10); #if TEST printf("After AX7303: bsize = %ld, free = %ld, blocks = %ld.\n" , bsize , free , blocks ); #endif if( cdrom_calls_used && bsize*blocks < cd_bsize*cd_blocks ) { /* useAX0x1510() was successful and is reporting bigger total size than INT21 AX=7303, so we use those values. If INT21 AX=7303 is reporting bigger total size than useAX0x1510(), it means the CD is bigger than a CD (e. g. it is a DVD-ROM). In that case we use the values from INT21 AX=7303. */ blocks = cd_blocks; free = cd_free; bsize = cd_bsize; } #if TEST printf("After AX7303+DVD chk: bsize = %ld, free = %ld, blocks = %ld.\n" , bsize , free , blocks ); #endif } } else { /* DOZE version earlier than 7.0. Use old method. */ if( ! cdrom_calls_used ) { if( use_AH0x36( drive_number, &blocks, &free, &bsize ) == -1 ) { /* use_AH0x36() sets errno on failure. */ return -1; } } #if TEST printf("After AX0x36: bsize = %ld, free = %ld, blocks = %ld.\n" , bsize , free , blocks ); #endif } /* Fill in the structure */ buf->f_bavail = free; buf->f_bfree = free; buf->f_blocks = blocks; buf->f_bsize = bsize; buf->f_ffree = free; buf->f_files = blocks; buf->f_type = 0; buf->f_fsid[0] = drive_number; buf->f_fsid[1] = MOUNT_UFS; buf->f_magic = FS_MAGIC; return 0; } #ifdef TEST #include #include int main (int argc, char *argv[]) { char *path; struct statfs fsbuf; if (argc > 1) path = argv[1]; else path = "."; errno = 0; if (statfs (path, &fsbuf) == 0) printf ("Results for `%s\':\n\nTotal blocks: %ld\nAvailable blocks: %ld\nBlock size: %ld\n", path, fsbuf.f_blocks, fsbuf.f_bfree, fsbuf.f_bsize); if (errno) perror (path); return 0; } #endif --=====================_7574008==_ Content-Type: text/plain; charset="us-ascii"; format=flowed --------------------------------------------------------- Peter J. Farley III (pjfarley AT dorsai DOT org OR pjfarley AT banet DOT net) --=====================_7574008==_--