delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/02/20/09:54:58

From: Martin Str|mberg <ams AT ludd DOT luth DOT se>
Message-Id: <199902201452.PAA19233@father.ludd.luth.se>
Subject: FAT32
To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS)
Date: Sat, 20 Feb 1999 15:52:43 +0100 (MET)
X-Mailer: ELM [version 2.4ME+ PL15 (25)]
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

Here's the complete patch, including corrections as Eli suggested.


New Model Army, The Love of Hopeless Causes,

							MartinS

diff -ruN src.org/libc/compat/mntent/mntent.c src/libc/compat/mntent/mntent.c
--- src.org/libc/compat/mntent/mntent.c	Sun Nov 15 14:20:56 1998
+++ src/libc/compat/mntent/mntent.c	Sun Jan 17 21:51:34 1999
@@ -368,26 +368,6 @@
 }
 
 /*
- * Return 1 if this drive is a CD-ROM drive, 0 otherwise.  Works
- * with MSCDEX 2.x, but what about other CD-ROM device drivers?
- */
-static int
-is_cdrom_drive(int drive_num)
-{
-  __dpmi_regs r;
-
-  r.x.ax = 0x150b;      /* CD-ROM Drive Check function */
-  r.x.cx = drive_num - 1; /* 0 = A: */
-  __dpmi_int(0x2f, &r);
-
-  /* If MSCDEX installed, BX will hold ADADh; AX will be non-zero
-     if this drive is supported by MSCDEX.  */
-  if (r.x.bx == 0xadad && r.x.ax != 0)
-    return 1;
-  return 0;
-}
-
-/*
  * Return 1 if a CD-ROM drive DRIVE_NUM is ready, i.e. there
  * is a disk in the drive and the tray door is closed.
  */
@@ -445,51 +425,6 @@
   return 0;
 }
 
-/*
- * Detect a RAM disk.  We do this by checking if the number of FAT
- * copies (in the Device Parameter Block) is 1, which is typical of
- * RAM disks.  [This doesn't _have_ to be so, but if it's good
- * enough for Andrew Schulman et al (Undocumented DOS, 2nd edition),
- * we can use this as well.]
- */
-static int
-is_ram_drive(int drive_num)
-{
-  __dpmi_regs r;
-
-  r.h.ah = 0x32;        /* Get Device Parameter Block function */
-  r.h.dl = drive_num;
-  __dpmi_int(0x21, &r);
-
-  if (r.h.al == 0)
-    {
-      /* The pointer to DPB is in DS:BX.  The number of FAT copies is at
-         offset 8 in the DPB.  */
-      char fat_copies = _farpeekb(dos_mem_base, MK_FOFF(r.x.ds, r.x.bx) + 8);
-
-      return fat_copies == 1;
-    }
-  return 0;
-}
-
-/*
- * Check if the media in this disk drive is fixed or removable.
- * Should only be called after we're sure this ain't CD-ROM or
- * RAM disk, since these might fool you with this call.
- */
-static int
-media_type(int drive_num)
-{
-  __dpmi_regs r;
-
-  r.x.ax = 0x4408;
-  r.h.bl = drive_num;
-  __dpmi_int(0x21, &r);
-
-  if (r.x.flags & 1)
-    return -1;
-  return r.x.ax;    /* returns 1 for fixed disks, 0 for removable */
-}
 
 /* Exported library functions.  */
 
@@ -700,11 +635,11 @@
           */
           if (mnt_type[0] == '?')
             {
-              int disk_type = media_type(drive_number);
+              int disk_type = _media_type(drive_number);
 
-              if (is_ram_drive(drive_number))
+              if (_is_ram_drive(drive_number))
                 mnt_type = NAME_ram;
-              else if (is_cdrom_drive(drive_number))
+              else if (_is_cdrom_drive(drive_number))
 		{
 		  /* Empty CD-ROM drives do NOT fail _truename(),
 		     so we must see if there is a disk in the drive.  */
diff -ruN src.org/libc/compat/sys/vfs/statfs.c src/libc/compat/sys/vfs/statfs.c
--- src.org/libc/compat/sys/vfs/statfs.c	Sun Dec 13 13:09:46 1998
+++ src/libc/compat/sys/vfs/statfs.c	Sat Jan 16 19:00:58 1999
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <dpmi.h>
 #include <go32.h>
+#include <dos.h>
 #include <libc/farptrgs.h>
 #include <errno.h>
 #include <unistd.h>
@@ -17,7 +18,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.  */
@@ -44,7 +47,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);
@@ -89,9 +92,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;
       }
@@ -100,26 +102,70 @@
 
   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);
+      /* 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)
+      /* 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? */
+     && blocks <= free /* Has free maxed out? */
+	)
     {
-      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, &regs);
+
+      /* Errors? */
+      if( regs.x.flags & 1 )
+      {
+	errno = ENODEV;
+	return( -1 );
+      }
+      
+      bsize = _farpeekw (_dos_ds, __tb + 0x2 + 0x2) * 
+	( _farpeekb (_dos_ds, __tb + 0x2 + 0x4) + 1 );
+      free = _farpeekw (_dos_ds, __tb + 0x2 + 0x1f) + 
+	65536 * _farpeekw (_dos_ds, __tb + 0x2 + 0x21);
+      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;
diff -ruN src.org/libc/compat/unistd/_llseek.c src/libc/compat/unistd/_llseek.c
--- src.org/libc/compat/unistd/_llseek.c	Thu Jan  1 00:00:00 1970
+++ src/libc/compat/unistd/_llseek.c	Sat Feb  6 14:24:28 1999
@@ -0,0 +1,128 @@
+/*
+ * File _llseek.c.
+ *
+ * Copyright (C) 1999 Martin Str”mberg <ams AT ludd DOT luth DOT se>.
+ *
+ * This software may be used freely so long as this copyright notice is
+ * left intact. There is no warranty on this software.
+ *
+ */
+
+#include <libc/stubs.h>
+#include <unistd.h>
+#include <limits.h>
+
+#if 0
+/* This #if 0ed code is an atempt to make _llseek() return correct
+   values when the file pointer is further than MAX_INT from the
+   beginning of the file. Unsuccessful so far. If you know the
+   solution let me know, thank you.
+   */
+
+#define SEEK_STEP (1<<30)
+
+static void
+do__llseek_from_0(int handle, offset_t offset)
+{
+
+  lseek(handle, 0, SEEK_SET);
+  while( offset )
+  {
+    if( INT_MAX < offset )
+    {
+      lseek(handle, INT_MAX, SEEK_CUR);
+      offset -= INT_MAX;
+    }
+    else
+    {
+      lseek(handle, offset, SEEK_CUR);
+      offset = 0;
+    }
+  }
+
+}
+
+
+static offset_t
+get_offset(int handle)
+{
+  long long real_offset;
+  off_t lseek_offset;
+  
+  real_offset = lseek(handle, 0, SEEK_CUR);
+
+  lseek(handle, -real_offset, SEEK_CUR);
+  /* Now we are on an 1<<31 (2^31) boundary. */
+
+  /* Try stepping backwards. */
+  lseek_offset = lseek(handle, -SEEK_STEP, SEEK_CUR);
+  while( lseek_offset )
+  {
+    /* We did move over zero, so this must be another chunk of 2^31 bytes. 
+     Move to the 1<<31 boundary. */
+    lseek(handle, -lseek_offset, SEEK_CUR);
+
+    /* Increase the real offset. */
+    real_offset += SEEK_STEP + lseek_offset;
+
+    /* Another step backwards... */
+    lseek_offset = lseek(handle, -SEEK_STEP, SEEK_CUR);
+  }
+
+  /* Reset file pointer to where we started. */
+  do__llseek_from_0(handle, real_offset);
+
+  return( real_offset );
+
+}
+#endif
+      
+
+offset_t
+_llseek(int handle, offset_t offset, int whence)
+{
+  /* Should it have an FS extension? 
+  __FSEXT_Function *func = __FSEXT_get_function(handle);
+  if (func)
+  {
+    int rv;
+    if (func(__FSEXT_llseek, &rv, &handle))
+      return rv;
+  }
+  */
+
+  int sign;
+  off_t lseek_offset = lseek(handle, 0, whence);  /* If we are seeking
+						     from beginning or
+						     end this sets the
+						     pointer there. */
+
+#if 0
+  tmp_offset = get_offset(handle);
+#endif
+
+  if( 0LL <= offset )
+  {
+    sign = 1;
+  }
+  else
+  {
+    sign = -1;
+  }
+  while( offset )
+  {
+    if( INT_MAX < sign*offset )
+    {
+      lseek(handle, sign*INT_MAX, SEEK_CUR);
+      offset -= sign*INT_MAX;
+    }
+    else
+    {
+      lseek_offset = lseek(handle, offset, SEEK_CUR);
+      offset = 0;
+    }
+  }
+
+  return( lseek_offset );
+
+}
diff -ruN src.org/libc/compat/unistd/_llseek.txh src/libc/compat/unistd/_llseek.txh
--- src.org/libc/compat/unistd/_llseek.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/compat/unistd/_llseek.txh	Fri Feb  5 23:41:06 1999
@@ -0,0 +1,55 @@
+@node _llseek, io
+@subheading Syntax
+
+@example
+#include <unistd.h>
+
+offset_t _llseek(int fd, offset_t offset, int whence);
+@end example
+
+@subheading Description
+
+This function moves the file pointer for @var{fd} according to
+@var{whence}:
+
+@table @code
+
+@item SEEK_SET
+
+The file pointer is moved to the offset specified.
+
+@item SEEK_CUR
+
+The file pointer is moved relative to its current position.
+
+@item SEEK_END
+
+The file pointer is moved to a position @var{offset} bytes from the end
+of the file.  The offset is usually nonpositive in this case. 
+
+@end table
+
+@var{offset} is of type long long, thus enabling you to seek with
+offsets as large as ~2^63.
+
+@subheading Return Value
+
+The new offset is returned. Note that due to limitations in the
+underlying DOS implementation only return values in the range 
+[0, MAX_INT] should be relied upon.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+long long ret;
+
+ret = _llseek(fd, (1<<32), SEEK_SET); /* Now ret equals 0 (unfortunately). */
+ret = _llseek(fd, -1, SEEK_CUR); /* Now ret equals 2^32-1 (good!). */
+ret = _llseek(fd, 0, SEEK_SET); /* Now ret equals 0 (good!). */
+ret = _llseek(fd, -1, SEEK_CUR); /* Now ret equals 2^32-1 (bad). */
+@end example
+
diff -ruN src.org/libc/compat/unistd/makefile src/libc/compat/unistd/makefile
--- src.org/libc/compat/unistd/makefile	Sun Jun 28 21:53:24 1998
+++ src/libc/compat/unistd/makefile	Sat Feb  6 00:16:44 1999
@@ -2,6 +2,7 @@
 # Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
 TOP=../..
 
+SRC += _llseek.c
 SRC += basename.c
 SRC += dirname.c
 SRC += fsync.c
diff -ruN src.org/libc/dos/dos/getfatsz.c src/libc/dos/dos/getfatsz.c
--- src.org/libc/dos/dos/getfatsz.c	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/getfatsz.c	Sat Jan  9 13:29:48 1999
@@ -0,0 +1,38 @@
+/*
+ * File getfatsz.c.
+ *
+ * Copyright (C) 1999 Martin Str”mberg <ams AT ludd DOT luth DOT se>.
+ *
+ * This software may be used freely so long as this copyright notice is
+ * left intact. There is no warranty on this software.
+ *
+ */
+
+#include <dpmi.h>
+#include <dos.h>
+
+/* Returns number of bits in FAT; 0 == FAT of unknown size; -1 == error. */
+int 
+_get_fat_size( const int drive /* drive number (1=A:). */
+	      )
+{
+  char s[9];
+  int n;
+  int size;
+
+  if( _get_fs_type( drive, s ) )
+  {
+    if( s[0] == 'F' && s[1] == 'A' && s[2] == 'T' )
+    {
+      size = 0;
+      for(n = 3; n < 8 && ( '0' <= s[n] && s[n] <= '9' ); n++)
+      {
+	size = 10*size + s[n] - '0';
+      }
+      
+      return( size );
+    }
+  }
+  
+  return( -1 );
+}
diff -ruN src.org/libc/dos/dos/getfatsz.txh src/libc/dos/dos/getfatsz.txh
--- src.org/libc/dos/dos/getfatsz.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/getfatsz.txh	Sun Jan 10 19:00:42 1999
@@ -0,0 +1,47 @@
+@node _get_fat_size, file system
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int _get_fat_size( const int drive );
+@end example
+
+@subheading Description
+
+This function tries to determine the number bits used to enumerate the
+clusters by the FAT on drive number @var{drive}. 1 == A:, 2 == B:,
+etc. 
+
+This function will not succeed on DOS version < 4.
+
+@subheading Return Value
+
+The number of bits used by the FAT (12, 16 or 32). 0 if the drive was
+formatted with FAT but of unknown size (NT reports that on FAT16). -1
+on error. 
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+int main(void)
+@{
+  int size;
+
+  size = _get_fs_type( 'C' - 'A' + 1 );
+  if( 0 <= size )
+  @{
+    printf("The size of FAT on C: is %d bits.\n", size);
+  @}
+
+  exit(0);
+@}
+
+@end example
diff -ruN src.org/libc/dos/dos/getfstyp.c src/libc/dos/dos/getfstyp.c
--- src.org/libc/dos/dos/getfstyp.c	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/getfstyp.c	Sat Jan  9 13:29:04 1999
@@ -0,0 +1,58 @@
+/*
+ * File getfstyp.c.
+ *
+ * Copyright (C) 1999 Martin Str”mberg <ams AT ludd DOT luth DOT se>.
+ *
+ * This software may be used freely so long as this copyright notice is
+ * left intact. There is no warranty on this software.
+ *
+ */
+
+#include <dos.h>
+#include <go32.h>
+#include <dpmi.h>
+#include <sys/farptr.h>
+
+/* Returns: 0 == error; 1 == result_str filled in. */
+int 
+_get_fs_type( const int drive /* drive number (1=A:). */
+	    , char *const result_str  /* String to put result in. At least 9 chars long. */
+	     )
+{
+  int n;
+  __dpmi_regs r;
+
+  /* Check DOZE version and return -1 if too low. */
+  if( ( _get_dos_version(1) >> 8) < 4 )
+  {
+    return( 0 );
+  }
+
+  /* Call INT21, ax==0x6900 i.e. Get Disk Serial Number (sic!). */
+  r.x.ax = 0x6900;
+  r.h.bl = drive; 
+  r.h.bh = 0;
+  r.x.ds = __tb >> 4;
+  r.x.dx = __tb & 0x0f;
+  __dpmi_int(0x21, &r);
+  if( (r.x.flags & 1) == 0 )
+  {
+    /* Get the file system type. */
+    for(n = 0; n < 8; n++)
+    {
+      result_str[n] = _farpeekb( _dos_ds, __tb + 0x11 + n);
+    }
+    result_str[8] = 0;
+
+    /* Remove terminating spaces. */
+    for(n = 7; n && result_str[n] == ' '; n-- )
+    {
+      result_str[n] = 0;
+    }
+
+    return( 1 );
+  }
+
+  return( 0 );
+
+}
diff -ruN src.org/libc/dos/dos/getfstyp.txh src/libc/dos/dos/getfstyp.txh
--- src.org/libc/dos/dos/getfstyp.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/getfstyp.txh	Sun Jan 10 19:00:46 1999
@@ -0,0 +1,48 @@
+@node _get_fs_type, file system
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int _get_fs_type( const int drive
+                , char *const result_str
+	         );
+@end example
+
+@subheading Description
+
+This function tries to extract the file system type of the drive
+number @var{drive}, 1 == A:, 2 == B:, etc. If successful the result
+is put in @var{result_str} which must be at least 9 characters long. 
+
+This function will not succeed on DOS version < 4 and is known to have
+trouble detecting the file system type of disks formatted with a later
+version of DOS than on the version it is run on. 
+
+@subheading Return Value
+
+1 if the file system type was extracted successfully; otherwise 0.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+int main(void)
+@{
+  char buffer[9];
+
+  if( _get_fs_type( 3, buffer ) )
+  @{
+    printf("The file system on C: is '%s'.\n", buffer);
+  @}
+
+  exit(0);
+@}
+
+@end example
diff -ruN src.org/libc/dos/dos/iscdrom.c src/libc/dos/dos/iscdrom.c
--- src.org/libc/dos/dos/iscdrom.c	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/iscdrom.c	Sun Jan 17 21:08:36 1999
@@ -0,0 +1,20 @@
+/* Copyright (c) 1995-98 Eli Zaretskii <eliz AT is DOT elta DOT co DOT il> */
+
+#include <dpmi.h>
+#include <dos.h>
+
+int
+_is_cdrom_drive(int drive_num)
+{
+  __dpmi_regs r;
+
+  r.x.ax = 0x150b;      /* CD-ROM Drive Check function */
+  r.x.cx = drive_num - 1; /* 0 = A: */
+  __dpmi_int(0x2f, &r);
+
+  /* If MSCDEX installed, BX will hold ADADh; AX will be non-zero
+     if this drive is supported by MSCDEX.  */
+  if (r.x.bx == 0xadad && r.x.ax != 0)
+    return 1;
+  return 0;
+}
diff -ruN src.org/libc/dos/dos/iscdrom.txh src/libc/dos/dos/iscdrom.txh
--- src.org/libc/dos/dos/iscdrom.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/iscdrom.txh	Sun Jan 17 19:57:10 1999
@@ -0,0 +1,45 @@
+@node _is_cdrom_drive, file system
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int _is_cdrom_drive( const int drive );
+@end example
+
+@subheading Description
+
+This function checks if drive number @var{drive} (1 == A:, 2 == B:,
+etc.) is a CD-ROM drive. Works with MSCDEX 2.x, but what about other
+CD-ROM device drivers? 
+
+@subheading Return Value
+
+1 if the drive is a CDROM drive, otherwise 0.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+int main(void)
+@{
+
+  if( _is_cdrom_drive( 'R' - 'A' + 1 ) )
+  @{
+    printf("C: is a CDROM drive.\n");
+  @}
+  else
+  @{
+    printf("C: is not a CDROM drive.\n");
+  @}
+
+  exit(0);
+@}
+
+@end example
diff -ruN src.org/libc/dos/dos/isfat32.c src/libc/dos/dos/isfat32.c
--- src.org/libc/dos/dos/isfat32.c	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/isfat32.c	Sun Jan 17 21:11:56 1999
@@ -0,0 +1,76 @@
+/*
+ * This is the file isfat32.c.
+ *
+ * Copyright (C) 1999 Martin Str”mberg <ams AT ludd DOT luth DOT se>.
+ *
+ * This software may be used freely so long as this copyright notice is
+ * left intact. There is no warranty on this software.
+ *
+ */
+
+#include <dos.h>
+
+static unsigned long checked = 0;
+static unsigned long removable = 0;
+static unsigned long fat32 = 0;
+
+/* Returns 1 if the drive is formatted with FAT32; 0 otherwise. */
+int 
+_is_fat32( const int drive /* drive number (1=A:). */
+	  )
+{
+  unsigned long mask;
+
+  /* Check input. */
+  if( 0 <= drive
+   && drive <= 32
+      )
+  {
+    /* Always check current drive (as we don't know if it's been changed). */
+    if( drive == 0 )
+    {
+      return( _get_fat_size( drive ) == 32 );
+    }
+    else
+    {
+      mask = 1 << ( drive - 1 );
+
+      /* Have we checked this drive for FAT32 yet and it isn't removable? */ 
+      if( checked & mask
+       && !( removable & mask ) )
+      {
+	return( ( fat32 & mask ) != 0 );
+      }
+
+      /* Always recheck removable drives. */
+      if( removable & mask )
+      {
+	return( _get_fat_size( drive ) == 32 );
+      }
+
+      /* Previously untested drive -> update tables. */
+
+      /* Is this a removable drive? (!_is_*_drive for _media_type problems.) */
+      if( !_is_ram_drive( drive )
+       && !_is_cdrom_drive( drive )
+       && _media_type( drive ) == 0 )
+      {
+	removable |= mask;
+	checked |= mask;
+	return( _get_fat_size( drive ) == 32 );
+      }
+
+      if( _get_fat_size( drive ) == 32 )
+      {
+	fat32 |= mask;
+      }
+
+      checked |= mask;
+
+      return( ( fat32 & mask ) != 0 );
+    }
+  }
+
+  /* Drives that don't exist can't be FAT32. */
+  return( 0 );
+}
diff -ruN src.org/libc/dos/dos/isfat32.txh src/libc/dos/dos/isfat32.txh
--- src.org/libc/dos/dos/isfat32.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/isfat32.txh	Sun Jan 17 21:04:52 1999
@@ -0,0 +1,47 @@
+@node _is_fat32, file system
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int _is_fat32( const int drive );
+@end example
+
+@subheading Description
+
+This function checks if drive number @var{drive} (1 == A:, 2 == B:,
+etc.) is formatted with FAT32. 
+
+For performance reasons the result is cached, hence if a drive is
+reformatted either from or to FAT32 a DJGPP program must be restarted.
+
+@subheading Return Value
+
+1 if the drive is formatted with FAT32, otherwise 0.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+int main(void)
+@{
+
+  if( _is_fat32( 'C' - 'A' + 1 ) )
+  @{
+    printf("C: is a FAT32 drive.\n");
+  @}
+  else
+  @{
+    printf("C: is not a FAT32 drive.\n");
+  @}
+
+  exit(0);
+@}
+
+@end example
diff -ruN src.org/libc/dos/dos/isramdri.c src/libc/dos/dos/isramdri.c
--- src.org/libc/dos/dos/isramdri.c	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/isramdri.c	Sun Jan 17 21:36:10 1999
@@ -0,0 +1,33 @@
+/* Copyright (c) 1995-98 Eli Zaretskii <eliz AT is DOT elta DOT co DOT il> */
+
+#include <dpmi.h>
+#include <go32.h>
+#include <sys/farptr.h>
+#include <dos.h>
+
+/* Macro to convert a segment and an offset to a "far offset" suitable
+   for _farxxx() functions of DJGPP.  */
+#ifndef MK_FOFF
+#define MK_FOFF(s,o) ((int)((((unsigned long)(unsigned short)(s)) << 4) + \
+                      (unsigned short)(o)))
+#endif
+
+int
+_is_ram_drive(int drive_num)
+{
+  __dpmi_regs r;
+
+  r.h.ah = 0x32;        /* Get Device Parameter Block function */
+  r.h.dl = drive_num;
+  __dpmi_int(0x21, &r);
+
+  if (r.h.al == 0)
+    {
+      /* The pointer to DPB is in DS:BX.  The number of FAT copies is at
+         offset 8 in the DPB.  */
+      char fat_copies = _farpeekb(_dos_ds, MK_FOFF(r.x.ds, r.x.bx) + 8);
+
+      return fat_copies == 1;
+    }
+  return 0;
+}
diff -ruN src.org/libc/dos/dos/isramdri.txh src/libc/dos/dos/isramdri.txh
--- src.org/libc/dos/dos/isramdri.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/isramdri.txh	Sun Jan 17 19:57:46 1999
@@ -0,0 +1,37 @@
+@node _is_ram_drive, file system
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int _is_ram_drive( const int drive );
+@end example
+
+@subheading Description
+
+This function checks if drive number @var{drive} (1 == A:, 2 == B:,
+etc.) is a RAM disk.  It is done by checking if the number of FAT
+copies (in the Device Parameter Block) is 1, which is typical of 
+RAM disks.  (This doesn't _have_ to be so, but if it's good enough for
+Andrew Schulman et al (Undocumented DOS, 2nd edition), we can use this
+as well.)
+
+@subheading Return Value
+
+1 if the drive is a RAM drive, otherwise 0.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+  int i = 4;
+
+  printf("%c: is a RAM drive: %d.\n",  'A' - 1 + i, _is_ram_drive( i ) )
+
+@end example
diff -ruN src.org/libc/dos/dos/makefile src/libc/dos/dos/makefile
--- src.org/libc/dos/dos/makefile	Sun Jun 18 02:50:38 1995
+++ src/libc/dos/dos/makefile	Sun Jan 17 19:50:06 1999
@@ -10,6 +10,8 @@
 SRC += getdfree.c
 SRC += getdinfo.c
 SRC += getdos_v.c
+SRC += getfatsz.c
+SRC += getfstyp.c
 SRC += getftime.c
 SRC += gettime.c
 SRC += gettimeo.c
@@ -17,6 +19,10 @@
 SRC += int86x.S
 SRC += intdos.c
 SRC += intdosx.c
+SRC += iscdrom.c
+SRC += isfat32.c
+SRC += isramdri.c
+SRC += mediatyp.c
 SRC += osflavor.c
 SRC += osmajor.c
 SRC += osminor.c
diff -ruN src.org/libc/dos/dos/mediatyp.c src/libc/dos/dos/mediatyp.c
--- src.org/libc/dos/dos/mediatyp.c	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/mediatyp.c	Sun Jan 17 21:36:06 1999
@@ -0,0 +1,18 @@
+/* Copyright (c) 1995-98 Eli Zaretskii <eliz AT is DOT elta DOT co DOT il> */
+
+#include <dpmi.h>
+#include <dos.h>
+
+int
+_media_type(int drive_num)
+{
+  __dpmi_regs r;
+
+  r.x.ax = 0x4408;
+  r.h.bl = drive_num;
+  __dpmi_int(0x21, &r);
+
+  if (r.x.flags & 1)
+    return -1;
+  return r.x.ax;    /* returns 1 for fixed disks, 0 for removable */
+}
diff -ruN src.org/libc/dos/dos/mediatyp.txh src/libc/dos/dos/mediatyp.txh
--- src.org/libc/dos/dos/mediatyp.txh	Thu Jan  1 00:00:00 1970
+++ src/libc/dos/dos/mediatyp.txh	Sun Jan 17 18:47:42 1999
@@ -0,0 +1,53 @@
+@node _media_type, file system
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int _media_type( const int drive );
+@end example
+
+@subheading Description
+
+This function checks if drive number @var{drive} (. 1 == A:, 2 == B:,
+etc.) is fixed or removable.
+
+@code{_media_type} should only be called after you are sure the drive
+isn't a CD-ROM or a RAM disk, since these might fool you with this
+call.  
+
+For performance reasons the result is cached.
+
+@subheading Return Value
+
+1 if the drive is a fixed disk, 0 if it is removable. -1 on error.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+Some work is needed here.
+
+
+int main(void)
+@{
+
+  if( _is_fat32( 'C' - 'A' + 1 ) )
+  @{
+    printf("C: is a FAT32 drive.\n");
+  @}
+  else
+  @{
+    printf("C: is not a FAT32 drive.\n");
+  @}
+
+  exit(0);
+@}
+
+@end example
diff -ruN src.org/libc/dos/io/_creat.c src/libc/dos/io/_creat.c
--- src.org/libc/dos/io/_creat.c	Sat Aug 31 22:09:32 1996
+++ src/libc/dos/io/_creat.c	Sun Jan 31 16:12:50 1999
@@ -6,6 +6,7 @@
 #include <go32.h>
 #include <dpmi.h>
 #include <io.h>
+#include <dos.h>
 #include <libc/dosio.h>
 #include <sys/fsext.h>
 
@@ -25,10 +26,15 @@
   if (__FSEXT_call_open_handlers(__FSEXT_creat, &rv, &filename))
     return rv;
 
-  _put_path(filename);
   if(use_lfn) {
     r.x.ax = 0x716c;
-    r.x.bx = 0x0002;		/* open r/w */
+    r.x.bx = 0x1002;		/* Open r/w with FAT32 extended size. */
+    r.x.dx = 0x0012;		/* Create, truncate if exists */
+    r.x.si = __tb_offset;
+  } else if(7 <= (_get_dos_version(1) >> 8)) {
+    r.x.ax = 0x6c00;
+    r.x.bx = 0x1002;		/* Open r/w with FAT32 extended size. */
+    /* FAT32 extended size flag doesn't help on WINDOZE 4.1 (98). */
     r.x.dx = 0x0012;		/* Create, truncate if exists */
     r.x.si = __tb_offset;
   } else {
@@ -37,6 +43,7 @@
   }
   r.x.cx = attrib;
   r.x.ds = __tb_segment;
+  _put_path(filename);
   __dpmi_int(0x21, &r);
   if(r.x.flags & 1)
   {
diff -ruN src.org/libc/dos/io/_creat.txh src/libc/dos/io/_creat.txh
--- src.org/libc/dos/io/_creat.txh	Sun Sep 27 15:21:32 1998
+++ src/libc/dos/io/_creat.txh	Sun Jan 31 20:54:50 1999
@@ -10,13 +10,22 @@
 @subheading Description
 
 This is a direct connection to the MS-DOS creat function call, int
-0x21, %ah = 0x3c.  The file is set to binary mode. This function can
-be hooked by the @xref{File System Extensions}. If you don't want this
-you should use @xref{_dos_creat} or @xref{_dos_creatnew}.
+0x21, %ah = 0x3c, on versions of DOS earlier than 7.0. On DOS version
+7.0 or later @code{_creat} calls function int 0x21, %ax = 0x6c00.
 
 On platforms where the LFN API (@pxref{_use_lfn, LFN}) is available,
 @code{_creat} calls function 0x716C of Interrupt 21h, to support long
 file names.
+
+On FAT32 file systems file size bigger than ~2^31 is supported. Note
+that WINDOWS 98 has a bug which only lets you create these big files
+if LFN is enabled. In plain DOS mode it plainly works.
+
+The file is set to binary mode. 
+
+This function can be hooked by the File System Extensions (@pxref{File
+System Extensions}. If you don't want this you should use
+@code{_dos_creat} or @code{_dos_creatnew}. 
 
 @subheading Return Value
 
diff -ruN src.org/libc/dos/io/_creat_n.c src/libc/dos/io/_creat_n.c
--- src.org/libc/dos/io/_creat_n.c	Sun Jun 28 22:42:16 1998
+++ src/libc/dos/io/_creat_n.c	Sun Jan 31 16:12:48 1999
@@ -27,6 +27,8 @@
 
   _put_path(filename);
   r.x.bx =
+    0x1000 |			/* FAT32 extended size. */
+    /* FAT32 extended size flag doesn't help on WINDOZE 4.1 (98). */
     0x2002 | (flags & 0xfff0);	/* r/w, no Int 24h, use caller-defined flags */
   r.x.dx = 0x0010;		/* Create, fail if exists */
   r.x.si = __tb_offset;
diff -ruN src.org/libc/dos/io/_open.c src/libc/dos/io/_open.c
--- src.org/libc/dos/io/_open.c	Sat Aug 31 22:09:32 1996
+++ src/libc/dos/io/_open.c	Sun Jan 31 16:09:36 1999
@@ -7,6 +7,7 @@
 #include <go32.h>
 #include <dpmi.h>
 #include <io.h>
+#include <dos.h>
 #include <libc/dosio.h>
 #include <sys/fsext.h>
 
@@ -26,12 +27,17 @@
   if (__FSEXT_call_open_handlers(__FSEXT_open, &rv, &filename))
     return rv;
 
-  _put_path(filename);
   if(use_lfn) {
     r.x.ax = 0x716c;
-    r.x.bx = oflag & 0xff;
+    r.x.bx = (oflag & 0xff) | 0x1000; /* 0x1000 is FAT32 extended size. */
     r.x.dx = 1;			/* Open existing file */
     r.x.si = __tb_offset;
+  } else if(7 <= (_get_dos_version(1) >> 8)) {
+    r.x.ax = 0x6c00;
+    r.x.bx = (oflag & 0xff) | 0x1000; /* 0x1000 is FAT32 extended size. */
+    /* FAT32 extended size flag doesn't help on WINDOZE 4.1 (98). */
+    r.x.dx = 1;			/* Open existing file */
+    r.x.si = __tb_offset;    
   } else {
     r.h.ah = 0x3d;
     r.h.al = oflag;
@@ -39,6 +45,7 @@
   }
   r.x.cx = 0;
   r.x.ds = __tb_segment;
+  _put_path(filename);
   __dpmi_int(0x21, &r);
   if(r.x.flags & 1)
   {
diff -ruN src.org/libc/dos/io/_open.txh src/libc/dos/io/_open.txh
--- src.org/libc/dos/io/_open.txh	Sun Sep 27 15:21:32 1998
+++ src/libc/dos/io/_open.txh	Sun Jan 31 20:54:48 1999
@@ -10,12 +10,21 @@
 @subheading Description
 
 This is a direct connection to the MS-DOS open function call, int 0x21,
-%ah = 0x3d.  (When long file names are supported, @code{_open} calls
-function 0x716c of Int 0x21.)  The file is set to binary mode.
+%ah = 0x3d, on versions of DOS earlier than 7.0. On DOS version 7.0 or
+later @code{_open} calls function int 0x21, %ax = 0x6c00. When long
+file names are supported, @code{_open} calls function 0x716c of int
+0x21.  
 
-This function can be hooked by the @xref{File System Extensions}.  If
-you don't want this you should use @xref{_dos_open} (but note that the
-latter doesn't support long file names).
+On FAT32 file systems file size bigger than ~2^31 is supported. Note
+that WINDOWS 98 has a bug which only lets you create these big files
+if LFN is enabled. In plain DOS mode it plainly works.
+
+The file is set to binary mode. 
+
+This function can be hooked by the File System Extensions (@pxref{File
+System Extensions}. If you don't want this you should use
+@code{_dos_open} (but note that the latter doesn't support long file
+names). 
 
 @subheading Return Value
 
diff -ruN src.org/libc/posix/sys/stat/xstat.c src/libc/posix/sys/stat/xstat.c
--- src.org/libc/posix/sys/stat/xstat.c	Tue Jan 23 22:30:20 1996
+++ src/libc/posix/sys/stat/xstat.c	Mon Feb  1 23:47:34 1999
@@ -159,25 +159,17 @@
 {
   static struct name_list  *name_list[256];
 
-  /* If the st_inode is wider than a short int, we will count up
-   * from USHRT_MAX+1 and thus ensure there will be no clashes with
-   * actual cluster numbers.
-   * Otherwise, we must count downward from USHRT_MAX, which could
-   * yield two files with identical inode numbers: one from actual
-   * DOS cluster number, and another from this function.  In the
-   * latter case, we still have at least 80 inode numbers before
-   * we step into potentially used numbers, because some FAT entries
-   * are reserved to mean EOF, unused entry and other special codes,
-   * and the FAT itself uses up some clusters which aren't counted.
+  /* We count downward from INT_MAX, which can't yield two files with
+   * identical inode numbers: FAT16 uses maximum ~2^16 and FAT32 uses
+   * maximum ~2^28. So in the worst case we have at least INT_MAX -
+   * 2^28 invented cluster numbers. When this is written this equals
+   * 2^31 - 2^28, which is > 2^30.
    */
-  static int         dir = (sizeof(ino_t) > 2 ? 1 : -1);
 
   /* INODE_COUNT is declared LONG and not ino_t, because some DOS-based
    * compilers use short or unsigned short for ino_t.
    */
-  static long        inode_count = (sizeof(ino_t) > 2
-                                    ? (long)USHRT_MAX + 1L
-                                    : USHRT_MAX);
+  static long        inode_count = INT_MAX; 
 
   struct name_list  *name_ptr, *prev_ptr;
   const char        *p;
@@ -187,7 +179,7 @@
   if (xstat_count != __bss_count)
     {
       xstat_count = __bss_count;
-      inode_count = (sizeof(ino_t) > 2 ? (long)USHRT_MAX + 1L : USHRT_MAX);
+      inode_count = INT_MAX; 
       memset (name_list, 0, sizeof name_list);
     }
 
@@ -219,7 +211,7 @@
     {
       ino_t retval = inode_count;
 
-      inode_count += dir;
+      inode_count--; 
       return retval;
     }
 
@@ -270,7 +262,7 @@
       else
         name_list[hash] = name_ptr;
       retval = inode_count;
-      inode_count += dir; /* increment or decrement as appropriate */
+      inode_count--; /* Decrement for next call. */
 
       return retval;
     }
diff -ruN include.org/dos.h include/dos.h
--- include.org/dos.h	Mon Sep  7 18:55:40 1998
+++ include/dos.h	Tue Jan 19 21:08:06 1999
@@ -134,6 +134,12 @@
 
 unsigned short _get_dos_version(int);
 
+int _get_fat_size(const int drive);
+int _get_fs_type(const int drive, char *const result_str);
+int _is_cdrom_drive(const int drive);
+int _is_fat32(const int drive);
+int _is_ram_drive(const int drive);
+int _media_type(const int drive);
 
 int int86(int ivec, union REGS *in, union REGS *out);
 int int86x(int ivec, union REGS *in, union REGS *out, struct SREGS *seg);
diff -ruN include.org/sys/djtypes.h include/sys/djtypes.h
--- include.org/sys/djtypes.h	Wed Sep  9 16:56:26 1998
+++ include/sys/djtypes.h	Fri Feb  5 23:42:46 1999
@@ -6,6 +6,7 @@
 #define __DJ_clock_t	typedef int clock_t;
 #define __DJ_gid_t	typedef int gid_t;
 #define __DJ_off_t	typedef int off_t;
+#define __DJ_offset_t	typedef long long offset_t;
 #define __DJ_pid_t	typedef int pid_t;
 #define __DJ_size_t	typedef long unsigned int size_t;
 #define __DJ_ssize_t	typedef int ssize_t;
diff -ruN include.org/sys/types.h include/sys/types.h
--- include.org/sys/types.h	Sat Feb 22 13:06:06 1997
+++ include/sys/types.h	Fri Feb  5 23:42:52 1999
@@ -24,6 +24,9 @@
 __DJ_off_t
 #undef __DJ_off_t
 #define __DJ_off_t
+__DJ_offset_t
+#undef __DJ_offset_t
+#define __DJ_offset_t
 __DJ_pid_t
 #undef __DJ_pid_t
 #define __DJ_pid_t
diff -ruN include.org/unistd.h include/unistd.h
--- include.org/unistd.h	Mon Jun 29 00:02:48 1998
+++ include/unistd.h	Fri Feb  5 23:44:40 1999
@@ -72,6 +72,7 @@
 
 void		__exit(int _status) __attribute__((noreturn));
 void		_exit(int _status) __attribute__((noreturn));
+offset_t       	_llseek(int _fildes, offset_t _offset, int _whence);
 int		access(const char *_path, int _amode);
 unsigned int	alarm(unsigned int _seconds);
 int		chdir(const char *_path);

- Raw text -


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