delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/01/05/23:25:28

From: Martin Str|mberg <ams AT ludd DOT luth DOT se>
Message-Id: <200101060425.FAA17064@father.ludd.luth.se>
Subject: Re: Fw: Patch for statfs.c
In-Reply-To: <OE57H69IsfV89a3KHtF00003709@hotmail.com> from Norberto Alfredo Bensa at "Jan 5, 2001 09:48:08 pm"
To: ceo AT nbensacomputers DOT com (Norberto Alfredo Bensa)
Date: Sat, 6 Jan 2001 05:25:10 +0100 (MET)
Cc: djgpp-workers AT delorie DOT com (DJGPP-WORKERS)
X-Mailer: ELM [version 2.4ME+ PL54 (25)]
MIME-Version: 1.0
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

According to Norberto Alfredo Bensa:
> Martin,
> 
> I've moved the CD-ROM calls down to the "one_more_try" part of the code,
> just before 213600. Can you please test if this now works with DVDs too?

Thank you!

Meanwhile I've been hacking it too. Would you be so kind as to try out
this code. Thanks!

Also I'm very interested in anyone running WINDOZE 95 _A_ to try this.

Then a question for the list: Is WINDOZE 95 B supposed to support
DVD-ROMs?


Right,

						MartinS

/* 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 <libc/stubs.h>
#include <string.h>
#include <dpmi.h>
#include <go32.h>
#include <dos.h>
#include <libc/farptrgs.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/vfs.h>
#include <libc/dosio.h>

static int /* Returns 0 == OK. Returns -1 => failure, errno set. */
use_AX0x1510_or_AH0x36( int drive_number, long *blocks, long *free,
			long *bsize )
{
  __dpmi_regs regs;
  int cdrom_calls_used = 0;

  /* 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, &regs);
  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, &regs);
      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, &regs);
      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);
	cdrom_calls_used = 1;
      }
    }
  }

  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, &regs);
    
    /* 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 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, &regs);
    drive_number = regs.h.al;
  }

  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, &regs);

    /* 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, &regs);
	
      /* Errors? */
      if( regs.x.flags & 1 )
      {
	/* If INT21 AX=7302 fails too, we revert to the old code. */
	if( use_AX0x1510_or_AH0x36( drive_number, &blocks, &free,
				    &bsize ) == -1 )
	{
	  return -1;
	}
      }
      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;
      }
    }
    else /* Use information from service AX=0x7303. */
    {
      free   = _farpeekl (_dos_ds, __tb + 0x0c);
      bsize  = _farpeekl (_dos_ds, __tb + 0x08)
	* _farpeekl (_dos_ds, __tb + 0x04);
      blocks = _farpeekl (_dos_ds, __tb + 0x10);
    }
  }
  else
  {
    /* DOZE version earlier than 7.0. Use old method. */
    if( use_AX0x1510_or_AH0x36( drive_number, &blocks, &free, &bsize )
	== -1 )
    {
      return -1;
    }
  }

  /* 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 <stdio.h>
#include <errno.h>

int main (int argc, char *argv[])
{
  char *path = ".";
  struct statfs fsbuf;

  if (argc > 1)
    path = argv[1];
  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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019