delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2000/01/29/09:34:11

From: Martin Str|mberg <ams AT ludd DOT luth DOT se>
Message-Id: <200001291155.MAA24655@father.ludd.luth.se>
Subject: FAT32 in one big one
To: djgpp AT delorie DOT com (DJGPP)
Date: Sat, 29 Jan 2000 12:55:53 +0100 (MET)
X-Mailer: ELM [version 2.4ME+ PL54 (25)]
MIME-Version: 1.0
Reply-To: djgpp AT delorie DOT com

Perhaps this can go in now when v2.03 has been released?


Right,

							MartinS

diff -ruN src.org/libc/compat/mntent/mntent.c src/libc/compat/mntent/mntent.c
--- src.org/libc/compat/mntent/mntent.c	Mon Apr 19 05:53:30 1999
+++ src/libc/compat/mntent/mntent.c	Sun Jan  9 21:55:18 2000
@@ -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	Wed Aug  4 15:58:24 1999
+++ src/libc/compat/sys/vfs/statfs.c	Sun Jan  9 22:08:26 2000
@@ -6,6 +6,7 @@
 #include <string.h>
 #include <dpmi.h>
 #include <go32.h>
+#include <dos.h>
 #include <libc/farptrgs.h>
 #include <errno.h>
 #include <unistd.h>
@@ -13,13 +14,19 @@
 #include <sys/vfs.h>
 #include <libc/dosio.h>
 
+#if 0
+#include <stdio.h>
+#endif
+
 int
 statfs(const char *path, struct statfs *buf)
 {
   __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 +53,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 +98,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;
       }
@@ -113,15 +119,72 @@
       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? */
+       )
+    {
+      /* 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 );
+      }
+
+      /* 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
+    }
   }
 
   /* 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	Fri Jan 28 21:53:44 2000
@@ -0,0 +1,36 @@
+/*
+ * 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 <dpmi.h>
+#include <errno.h>
+#include <libc/dosio.h>
+
+
+offset_t
+_llseek(int handle, offset_t offset, int whence)
+{
+  __dpmi_regs r;
+
+  r.h.ah = 0x42;
+  r.h.al = whence;
+  r.x.bx = handle;
+  r.x.cx = offset >> 16;
+  r.x.dx = offset & 0xffff;
+  __dpmi_int(0x21, &r);
+  if (r.x.flags & 1)
+  {
+    errno = __doserr_to_errno(r.x.ax);
+    return -1;
+  }
+  return( ( ( (unsigned)r.x.dx ) << 16) + r.x.ax );
+}
+
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~	Fri Jan 28 20:44:24 2000
@@ -0,0 +1,88 @@
+/*
+ * 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 <dpmi.h>
+#include <errno.h>
+#include <libc/dosio.h>
+
+
+static offset_t
+ll_llseek(int handle, offset_t offset, int whence)
+{
+  __dpmi_regs r;
+
+  r.h.ah = 0x42;
+  r.h.al = whence;
+  r.x.bx = handle;
+  r.x.cx = offset >> 16;
+  r.x.dx = offset & 0xffff;
+  __dpmi_int(0x21, &r);
+  if (r.x.flags & 1)
+  {
+    errno = __doserr_to_errno(r.x.ax);
+    return -1;
+  }
+  return( ( ( (unsigned)r.x.dx ) << 16) + r.x.ax );
+}
+
+
+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;
+  }
+  */
+
+  offset_t position;
+
+  /* We convert SEEK_CUR and SEEK_END to SEEK_SET. */  
+  if( whence == SEEK_CUR || whence == SEEK_END )
+  {
+    position = ll_llseek( handle, 0, whence );
+    if( position < 0 )
+    {
+      /* Seek failed. */
+      return( -1 );
+    }
+
+    whence = SEEK_SET;
+    offset = position + offset;
+  }
+
+  /* Obviously, this part must be after conversion to SEEK_SET. */
+  if( whence == SEEK_SET )
+  {
+    if( offset < 0 )
+    {
+      offset = 0;
+    }
+    else if( MAX_FILE_POINTER_POSITION < offset )
+    {
+      offset = MAX_FILE_POINTER_POSITION;
+    }
+  }
+  else
+  {
+    errno = EINVAL;
+    return( -1 );
+  }
+
+  return( ll_llseek( handle, offset, whence ) );
+
+}
+
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	Sat Jan 29 11:26:52 2000
@@ -0,0 +1,66 @@
+@ignore
+ * File _llseek.txh.
+ *
+ * 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.
+ *
+@ignore end
+
+@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 (FAT16 limits this to ~2^31; FAT32 limits
+this to 2^32-2).
+
+@subheading Return Value
+
+The new offset is returned. Note that due to limitations in the
+underlying DOS implementation the offset wraps around to 0 at offset
+2^32. -1 means the call failed.
+
+@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/_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~	Mon Jan 10 19:36:28 2000
@@ -0,0 +1,66 @@
+@ignore
+ * File _llseek.txh.
+ *
+ * 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.
+ *
+@ignore end
+
+@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 (FAT16 limits this to ~2^31; FAT32 limits
+this to 2^32-2).
+
+@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, 2^32-2] should be relied upon. -1 means the call failed.
+
+@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 17:53:24 1998
+++ src/libc/compat/unistd/makefile	Sun Jan  9 22:10:46 2000
@@ -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	Fri Nov 12 19:17:36 1999
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * FAT size algorithm according to "Hardware White Paper, FAT: General 
+ * Overwiew of On-Disk Format" version 1.02, May 5, 1999, Microsoft 
+ * Corporation. Downloadable from <http://www.microsoft.com/hwdev/>.
+ *
+ */
+
+#include <dos.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <errno.h>
+#include <sys/farptr.h>
+
+/* Returns number of bits in FAT; -1 == error. */
+int 
+_get_fat_size( const int drive /* drive number (1=A:). */
+	      )
+{
+  __dpmi_regs r = {{0}};
+  int size;
+  unsigned long bytes_per_sector, sectors_per_cluster, reserved_sectors;
+  unsigned long number_of_fats, root_entries, fat16_size, fat32_size;
+  unsigned long total16_sectors, total32_sectors;
+  unsigned long root_sectors, fat_size, total_sectors, data_sectors;
+  unsigned long number_of_clusters;
+  char file_system_string[9];
+  
+  /* First check that we have a FAT file system. */
+  if( ! _get_fs_type( drive, file_system_string ) 
+   || file_system_string[0] != 'F' 
+   || file_system_string[1] != 'A'
+   || file_system_string[2] != 'T' )
+  {
+    errno = ENOSYS;
+    return( -1 );
+  }
+
+  r.x.ax = 0x440d;
+  r.h.bl = drive;
+  r.h.ch = 0x48; /* First we try a FAT32 disk drive. */
+  r.h.cl = 0x60;
+  r.x.ds = r.x.si = __tb >>4;
+  r.x.dx = r.x.di = __tb & 0x0f;
+
+  __dpmi_int(0x21, &r);
+  if( r.x.flags & 0x01 )
+  {
+    /* Hmmpf! That didn't work; fall back to disk drive. */
+    r.x.ax = 0x440d;
+    r.h.bl = drive;
+    r.h.ch = 0x08; /* Disk drive. */ 
+    r.h.cl = 0x60;
+    r.x.ds = r.x.si = __tb >>4;
+    r.x.dx = r.x.di = __tb & 0x0f;
+
+    __dpmi_int(0x21, &r);
+    if( r.x.flags & 0x01 )
+    {
+      errno = ENOSYS;
+      return(-1);
+    }
+  }
+
+  /* +7 is offset in RBIL, the changing number is offset according to 
+     Microsnoft's document and -11 is a corrective offset (the Microsnoft 
+     document starts its offset counting 11 to early, freely mixing in the 
+     boot sector). */
+  bytes_per_sector = _farpeekw(_dos_ds, __tb+7+11-11);
+  sectors_per_cluster = _farpeekb(_dos_ds, __tb+7+13-11);
+  reserved_sectors = _farpeekw(_dos_ds, __tb+7+14-11);
+  number_of_fats = _farpeekb(_dos_ds, __tb+7+16-11);
+  root_entries = _farpeekw(_dos_ds, __tb+7+17-11);
+  fat16_size = _farpeekw(_dos_ds, __tb+7+22-11);
+  fat32_size = _farpeekl(_dos_ds, __tb+7+36-11);
+  total16_sectors = _farpeekw(_dos_ds, __tb+7+19-11);
+  total32_sectors = _farpeekl(_dos_ds, __tb+7+32-11);
+  
+  /* Check sectors_per_cluster, which might be zero. */
+  if( sectors_per_cluster == 0 )
+  {
+    errno = ENOSYS;
+    return( -1 );
+  }
+
+  /* Do the calculations. */
+  root_sectors = ( (root_entries * 32) 
+		 + (bytes_per_sector - 1)
+		   ) / bytes_per_sector;
+  fat_size = fat16_size ? fat16_size : fat32_size;
+  total_sectors = total16_sectors ? total16_sectors : total32_sectors;
+  data_sectors = total_sectors - reserved_sectors - number_of_fats*fat_size
+    - root_sectors;
+  number_of_clusters = data_sectors / sectors_per_cluster;
+  if( number_of_clusters < 4085 )
+  {
+    size = 12;
+  }
+  else if( number_of_clusters < 65525 )
+  {
+    size = 16;
+  }
+  else
+  {
+    size = 32;
+  }
+
+#if 0
+#include <stdio.h>
+  fprintf(stderr, "bytes_per_sector = %ld.\n", bytes_per_sector);
+  fprintf(stderr, "sectors_per_cluster = %ld.\n", sectors_per_cluster);
+  fprintf(stderr, "reserved_sectors = %ld.\n", reserved_sectors);
+  fprintf(stderr, "number_of_fats = %ld.\n", number_of_fats);
+  fprintf(stderr, "root_entries = %ld.\n", root_entries);
+  fprintf(stderr, "fat16_size = %ld.\n", fat16_size);
+  fprintf(stderr, "fat32_size = %ld.\n", fat32_size);
+  fprintf(stderr, "total16_sectors = %ld.\n", total16_sectors);
+  fprintf(stderr, "total32_sectors = %ld.\n", total32_sectors);
+  fprintf(stderr, "root_sectors = %ld.\n", root_sectors);
+  fprintf(stderr, "data_sectors = %ld.\n", data_sectors);
+  fprintf(stderr, "number_of_clusters = %ld.\n", number_of_clusters);
+#endif
+
+  return( size );
+  
+}
+
+#if 0
+int main(int argc, char *argv[])
+{
+  int ret;
+  
+  if( argc == 2
+   && 'A' <= argv[1][0] 
+   && argv[1][0] <= 'Z' )
+  {
+    
+    ret = _get_fat_size(argv[1][0] - 'A' + 1);
+    fprintf(stderr, "_get_fat_size returned %d.\n", ret);
+
+    return(0);
+  }
+  else
+  {
+    fprintf(stderr, "%s: run like this '%s C'.\n", argv[0], argv[0]);
+    
+    return(1);
+  }
+
+}
+#endif
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	Fri Nov 12 18:49:44 1999
@@ -0,0 +1,61 @@
+@ignore
+ * 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.
+ *
+@end ignore
+
+@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., 0 == default drive.
+
+This function will not succeed on DOS version < 4, setting
+@code{errno} to @code{ENOSYS}. It is also 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. E. g. floppies with LFN
+entries can cause this function to fail or detect the fat size as 16
+if used in plain DOS.
+
+@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_fat_size( '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 Mar 13 18:30:00 1999
@@ -0,0 +1,62 @@
+/*
+ * 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 <errno.h>
+#include <go32.h>
+#include <dpmi.h>
+#include <libc/dosio.h>
+#include <sys/farptr.h>
+
+/* Returns: -1 == error; 0 == 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 )
+  {
+    errno = ENOSYS;
+    return( -1 );
+  }
+
+  /* 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( 0 );
+  }
+
+  errno = __doserr_to_errno(r.x.ax);
+  return( -1 );
+
+}
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	Tue Nov 16 19:05:16 1999
@@ -0,0 +1,61 @@
+@ignore
+ * 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.
+ *
+@end ignore
+
+@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., 0 == default drive. 
+
+If successful the result is put in @var{result_str} which must be at 
+least 9 characters long. If unsuccessful errno is set.
+
+This function will not succeed on DOS version < 4, setting
+@code{errno} to @code{ENOSYS}. It is also 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. E. g. floppies with LFN
+entries can cause this function to fail or detect the floppy as
+FAT16 if used in plain DOS. 
+
+@subheading Return Value
+
+0 if the file system type was extracted successfully; otherwise -1.
+
+@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 Feb 28 11:47:34 1999
@@ -0,0 +1,87 @@
+/*
+ * 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>
+#include <libc/bss.h>
+
+static unsigned long checked = 0;
+static unsigned long removable = 0;
+static unsigned long fat32 = 0;
+static int isfat32_bss_count = -1;
+
+/* 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
+      )
+  {
+    /* Reinitialise if needed (emacs dump). */
+    if( isfat32_bss_count != __bss_count)
+    {
+      isfat32_bss_count = __bss_count;
+      checked = 0;
+      removable = 0;
+      fat32 = 0;
+    }
+
+    /* 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	Tue Nov 16 19:05:24 1999
@@ -0,0 +1,55 @@
+@ignore
+ * 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.
+ *
+@end ignore
+
+@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	Sat Mar 13 18:16:18 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 @emph{have} to be so, but if it's good
+enough for Andrew Schulman et al (@cite{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 01:50:38 1995
+++ src/libc/dos/dos/makefile	Sun Jan  9 22:15:56 2000
@@ -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	Sat Mar 13 18:16:16 1999
@@ -0,0 +1,48 @@
+@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., 0 == default drive) 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.  
+
+@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>
+
+int main(void)
+@{
+
+  if( _media_type( 'C' - 'A' + 1 ) )
+  @{
+    printf("C: is (probably) a hard drive.\n");
+  @}
+  else
+  @{
+    printf("C: is (probably) a removable 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 18:09:32 1996
+++ src/libc/dos/io/_creat.c	Sun Jan  9 23:12:48 2000
@@ -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,18 +26,24 @@
   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 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 {
     r.h.ah = 0x3c;
     r.x.dx = __tb_offset;
   }
   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 Jun 20 04:53:34 1999
+++ src/libc/dos/io/_creat.txh	Mon Jan 10 18:27:20 2000
@@ -10,14 +10,23 @@
 @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 @dfn{File System Extensions}, see @ref{File System
-Extensions}.  If you don't want this, you should use @code{_dos_creat}
-(@pxref{_dos_creat}) or @code{_dos_creatnew} (@pxref{_dos_creatnew}).
+%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 sizes up to 2^32-2 are 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 @dfn{File System Extensions}, see
+@ref{File System Extensions}.  If you don't want this, you should use
+@code{_dos_creat} (@pxref{_dos_creat}) or @code{_dos_creatnew}
+(@pxref{_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 18:42:16 1998
+++ src/libc/dos/io/_creat_n.c	Mon Jan 10 18:21:00 2000
@@ -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 17:09:32 1996
+++ src/libc/dos/io/_open.c	Mon Jan 10 18:55:42 2000
@@ -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 Jun 20 04:53:34 1999
+++ src/libc/dos/io/_open.txh	Mon Jan 10 18:27:04 2000
@@ -10,8 +10,16 @@
 @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.
+
+On FAT32 file systems file sizes up to 2^32-2 are 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 @dfn{File System Extensions}
 (@pxref{File System Extensions}).  If you don't want this, you should
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 Jan 10 18:36:04 2000
@@ -159,25 +159,16 @@
 {
   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 upwards from 2^28+1, which can't yield two files with
+   * identical inode numbers: FAT16 uses maximum ~2^16 and FAT32 uses
+   * maximum ~2^28. 
    */
-  static int         dir = (sizeof(ino_t) > 2 ? 1 : -1);
+#define INVENTED_INODE_START ( (1 << 28) + 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 = INVENTED_INODE_START;
 
   struct name_list  *name_ptr, *prev_ptr;
   const char        *p;
@@ -187,7 +178,7 @@
   if (xstat_count != __bss_count)
     {
       xstat_count = __bss_count;
-      inode_count = (sizeof(ino_t) > 2 ? (long)USHRT_MAX + 1L : USHRT_MAX);
+      inode_count = INVENTED_INODE_START;
       memset (name_list, 0, sizeof name_list);
     }
 
@@ -219,7 +210,7 @@
     {
       ino_t retval = inode_count;
 
-      inode_count += dir;
+      inode_count++;
       return retval;
     }
 
@@ -270,7 +261,7 @@
       else
         name_list[hash] = name_ptr;
       retval = inode_count;
-      inode_count += dir; /* increment or decrement as appropriate */
+      inode_count++; /* Increment for next call. */
 
       return retval;
     }

- Raw text -


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