delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/06/10/09:04:00

From: Martin Str|mberg <ams AT ludd DOT luth DOT se>
Message-Id: <200006101303.PAA17488@father.ludd.luth.se>
Subject: LONG: fat32 diff in cvs (second try)
To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS)
Date: Sat, 10 Jun 2000 15:03:27 +0200 (MET DST)
X-Mailer: ELM [version 2.4ME+ PL54 (25)]
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

Ok-dokey! I think I have fixed all Eli's comments, including adding
some more text to the description of _get_fat_size() and
_get_fs_type().


Right,

							MartinS

Index: djgpp/include/dos.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/dos.h,v
retrieving revision 1.5
diff -p -3 -r1.5 dos.h
*** dos.h	1999/06/03 17:22:28	1.5
--- dos.h	2000/06/10 12:51:09
*************** extern int		_doserrno;
*** 135,140 ****
--- 135,146 ----
  
  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);
Index: djgpp/include/unistd.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/unistd.h,v
retrieving revision 1.5
diff -p -3 -r1.5 unistd.h
*** unistd.h	1999/12/24 22:08:40	1.5
--- unistd.h	2000/06/10 12:51:09
*************** pid_t		getppid(void);
*** 102,107 ****
--- 102,108 ----
  uid_t		getuid(void);
  int		isatty(int _fildes);
  int		link(const char *_existing, const char *_new);
+ offset_t	llseek(int _fildes, offset_t _offset, int _whence);
  off_t		lseek(int _fildes, off_t _offset, int _whence);
  long		pathconf(const char *_path, int _name);
  int		pause(void);
Index: djgpp/include/sys/djtypes.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/djtypes.h,v
retrieving revision 1.4
diff -p -3 -r1.4 djtypes.h
*** djtypes.h	1999/12/14 11:57:45	1.4
--- djtypes.h	2000/06/10 12:51:10
***************
*** 7,12 ****
--- 7,13 ----
  #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;
Index: djgpp/include/sys/fsext.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/fsext.h,v
retrieving revision 1.3
diff -p -3 -r1.3 fsext.h
*** fsext.h	1998/06/28 21:17:44	1.3
--- fsext.h	2000/06/10 12:51:10
*************** typedef enum {
*** 31,37 ****
    __FSEXT_dup,
    __FSEXT_dup2,
    __FSEXT_fstat,
!   __FSEXT_stat
  } __FSEXT_Fnumber;
  
  /* _ready gets passed a fd and should return a mask of these,
--- 31,38 ----
    __FSEXT_dup,
    __FSEXT_dup2,
    __FSEXT_fstat,
!   __FSEXT_stat,
!   __FSEXT_llseek
  } __FSEXT_Fnumber;
  
  /* _ready gets passed a fd and should return a mask of these,
Index: djgpp/include/sys/types.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/sys/types.h,v
retrieving revision 1.4
diff -p -3 -r1.4 types.h
*** types.h	1999/06/03 17:22:29	1.4
--- types.h	2000/06/10 12:51:10
*************** __DJ_gid_t
*** 25,30 ****
--- 25,33 ----
  __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
Index: djgpp/src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.1
diff -p -3 -r1.1 wc204.txi
*** wc204.txi	2000/05/30 18:07:38	1.1
--- wc204.txi	2000/06/10 12:51:11
***************
*** 1,7 ****
  @node Changes in 2.04, , Changes in 2.03, What Changed
  @section Changes in 2.04
  
! Here is a list of changes from DJGPP V2.03 to V2.04.
  
  @findex uname AT r{, CPU type detection}
! Ability to report the exact CPU type in @code{uname}.
--- 1,40 ----
  @node Changes in 2.04, , Changes in 2.03, What Changed
  @section Changes in 2.04
  
! Here is a list of changes from DJGPP V2.03 to V2.04.  
  
  @findex uname AT r{, CPU type detection}
! Ability to report the exact CPU type in @code{uname}.  
! 
! @findex _creat AT r{, and FAT32}
! @findex _creatnew AT r{, and FAT32}
! @findex _open AT r{, and FAT32}
! The functions @code{_creat}, @code{_creatnew} and @code{_open} now set
! extended size flag in DOS calls to be able to create files with size up
! to 2^32-1, supported on FAT32 volumes.  
! 
! @findex llseek AT r{, and FAT32}
! The function @code{llseek} added with type @code{offset_t} to support
! file seeks up to 2^32-2.  
! 
! @findex statfs AT r{, and FAT32}
! The function @code{statfs} have been made to report correct values >
! 2^31 on FAT32 partitions.  
! 
! @findex _invent_inode AT r{, and FAT32}
! The function @code{_invent_inode} has been changed to start numbering
! invented inodes from @code{USHRT_MAX+1} to @code{2^28+1}.  
! 
! @findex _is_cdrom_drive
! @findex _is_ram_drive
! @findex _media_type
! Functions @code{_is_cdrom_drive}, @code{_is_ram_drive} and
! @code{_media_type} has been taken out of @file{mntent.c} and made
! externally callable.   
! 
! @findex _get_fat_size
! @findex _get_fs_type
! @findex _is_fat32
! New functions @code{_get_fat_size}, @code{_get_fs_type} and
! @code{_is_fat32} added.
! 
Index: djgpp/src/libc/compat/mntent/mntent.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/mntent/mntent.c,v
retrieving revision 1.5
diff -p -3 -r1.5 mntent.c
*** mntent.c	1999/04/19 09:53:30	1.5
--- mntent.c	2000/06/10 12:51:21
*************** get_netredir_entry(int drive_num)
*** 368,393 ****
  }
  
  /*
-  * 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.
   */
--- 368,373 ----
*************** cdrom_drive_ready(int drive_num)
*** 445,495 ****
    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.  */
  
--- 425,430 ----
*************** getmntent(FILE *filep)
*** 700,710 ****
            */
            if (mnt_type[0] == '?')
              {
!               int disk_type = media_type(drive_number);
  
!               if (is_ram_drive(drive_number))
                  mnt_type = NAME_ram;
!               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.  */
--- 635,645 ----
            */
            if (mnt_type[0] == '?')
              {
!               int disk_type = _media_type(drive_number);
  
!               if (_is_ram_drive(drive_number))
                  mnt_type = NAME_ram;
!               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.  */
Index: djgpp/src/libc/compat/sys/vfs/statfs.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/sys/vfs/statfs.c,v
retrieving revision 1.4
diff -p -3 -r1.4 statfs.c
*** statfs.c	1999/08/04 19:58:23	1.4
--- statfs.c	2000/06/10 12:51:21
***************
*** 6,11 ****
--- 6,12 ----
  #include <string.h>
  #include <dpmi.h>
  #include <go32.h>
+ #include <dos.h>
  #include <libc/farptrgs.h>
  #include <errno.h>
  #include <unistd.h>
***************
*** 13,25 ****
  #include <sys/vfs.h>
  #include <libc/dosio.h>
  
  int
  statfs(const char *path, struct statfs *buf)
  {
    __dpmi_regs regs;
    int drive_number;
    int cdrom_calls_used = 0;
!   int blocks = 0;
  
    /* Get the drive number, including the case of magic
       names like /dev/c/foo.  */
--- 14,32 ----
  #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;
!   long blocks = 0;
!   long free = 0;
!   long bsize = 0;
  
    /* Get the drive number, including the case of magic
       names like /dev/c/foo.  */
*************** statfs(const char *path, struct statfs *
*** 46,52 ****
    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;
  
      /* Construct the request header for the CD-ROM device driver.  */
      memset (request_header, 0, sizeof request_header);
--- 53,59 ----
    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);
*************** statfs(const char *path, struct statfs *
*** 91,99 ****
        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 */
  	blocks  = _farpeekl (_dos_ds, __tb + 1);
  	cdrom_calls_used = 1;
        }
--- 98,105 ----
        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;
        }
*************** statfs(const char *path, struct statfs *
*** 113,127 ****
        errno = ENODEV;
        return -1;
      }
      blocks = regs.x.dx;
    }
  
    /* Fill in the structure */
!   buf->f_bavail = regs.x.bx;
!   buf->f_bfree = regs.x.bx;
    buf->f_blocks = blocks;
!   buf->f_bsize = regs.x.cx * regs.x.ax;
!   buf->f_ffree = regs.x.bx;
    buf->f_files = blocks;
    buf->f_type = 0;
    buf->f_fsid[0] = drive_number;
--- 119,190 ----
        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 = 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;
Index: djgpp/src/libc/compat/unistd/llseek.c
===================================================================
RCS file: llseek.c
diff -N llseek.c
*** /dev/null	Tue May  5 16:32:27 1998
--- llseek.c	Sat Jun 10 08:51:22 2000
***************
*** 0 ****
--- 1,47 ----
+ /*
+  * File llseek.c.
+  *
+  * Copyright (C) 2000 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>
+ #include <sys/fsext.h>
+ 
+ 
+ offset_t
+ llseek( int handle, offset_t offset, int whence )
+ {
+   __dpmi_regs r;
+ 
+   __FSEXT_Function *func = __FSEXT_get_function(handle);
+   if( func )
+   {
+     int rv;
+     if( func(__FSEXT_llseek, &rv, &handle) )
+     {
+       return rv;
+     }
+   }
+ 
+   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 );
+ }
+ 
Index: djgpp/src/libc/compat/unistd/llseek.txh
===================================================================
RCS file: llseek.txh
diff -N llseek.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- llseek.txh	Sat Jun 10 08:51:22 2000
***************
*** 0 ****
--- 1,66 ----
+ @ignore
+  * File llseek.txh.
+  *
+  * Copyright (C) 2000 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 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
+ 
Index: djgpp/src/libc/compat/unistd/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/makefile,v
retrieving revision 1.2
diff -p -3 -r1.2 makefile
*** makefile	1998/06/28 21:53:24	1.2
--- makefile	2000/06/10 12:51:22
*************** SRC += getdtabl.c
*** 10,15 ****
--- 10,16 ----
  SRC += gethostn.c
  SRC += getpages.c
  SRC += getwd.c
+ SRC += llseek.c
  SRC += nice.c
  SRC += sync.c
  SRC += truncate.c
Index: djgpp/src/libc/dos/dos/getfatsz.c
===================================================================
RCS file: getfatsz.c
diff -N getfatsz.c
*** /dev/null	Tue May  5 16:32:27 1998
--- getfatsz.c	Sat Jun 10 08:51:23 2000
***************
*** 0 ****
--- 1,133 ----
+ /*
+  * File getfatsz.c.
+  *
+  * Copyright (C) 2000 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 );
+   
+ }
+ 
Index: djgpp/src/libc/dos/dos/getfatsz.txh
===================================================================
RCS file: getfatsz.txh
diff -N getfatsz.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- getfatsz.txh	Sat Jun 10 08:51:24 2000
***************
*** 0 ****
--- 1,64 ----
+ @ignore
+  * Copyright (C) 2000 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 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.  
+ 
+ If you are looking for a function that is able to detect other file
+ systems, perhaps the function @xref{_get_fs_type} can be of use.
+ 
+ @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
Index: djgpp/src/libc/dos/dos/getfstyp.c
===================================================================
RCS file: getfstyp.c
diff -N getfstyp.c
*** /dev/null	Tue May  5 16:32:27 1998
--- getfstyp.c	Sat Jun 10 08:51:24 2000
***************
*** 0 ****
--- 1,62 ----
+ /*
+  * File getfstyp.c.
+  *
+  * Copyright (C) 2000 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 );
+ 
+ }
Index: djgpp/src/libc/dos/dos/getfstyp.txh
===================================================================
RCS file: getfstyp.txh
diff -N getfstyp.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- getfstyp.txh	Sat Jun 10 08:51:24 2000
***************
*** 0 ****
--- 1,69 ----
+ @ignore
+  * Copyright (C) 2000 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.  It
+ does this by calling INT21, AX=0x6900, Get Disk Serial Number (sic!),
+ which returns, among other things, an eight character field which is
+ set while formatting the drive. Now, this field can be set to whatever
+ the formatting program wishes, but so far every FAT formatted drive
+ has returned a string starting with "FAT".  
+ 
+ If successful the result is put in @var{result_str} which must be at 
+ least 9 characters long.  If unsuccessful @code{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 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.  
+ 
+ If you are interested in which kind of FAT file system that is in use
+ try the function @xref{_get_fat_size} which will reliably detect the
+ right kind of FAT file system.  
+ 
+ @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
Index: djgpp/src/libc/dos/dos/iscdrom.c
===================================================================
RCS file: iscdrom.c
diff -N iscdrom.c
*** /dev/null	Tue May  5 16:32:27 1998
--- iscdrom.c	Sat Jun 10 08:51:24 2000
***************
*** 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;
+ }
Index: djgpp/src/libc/dos/dos/iscdrom.txh
===================================================================
RCS file: iscdrom.txh
diff -N iscdrom.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- iscdrom.txh	Sat Jun 10 08:51:24 2000
***************
*** 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.  It works with MSCDEX 2.x and Windows 9X
+ built-in CDFS support.  
+ 
+ @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
Index: djgpp/src/libc/dos/dos/isfat32.c
===================================================================
RCS file: isfat32.c
diff -N isfat32.c
*** /dev/null	Tue May  5 16:32:27 1998
--- isfat32.c	Sat Jun 10 08:51:24 2000
***************
*** 0 ****
--- 1,29 ----
+ /*
+  * This is the file isfat32.c.
+  *
+  * Copyright (C) 2000 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>
+ 
+ /* Returns 1 if the drive is formatted with FAT32; 0 otherwise. */
+ int 
+ _is_fat32( const int drive /* drive number (1=A:). */
+ 	  )
+ {
+   /* Check input. */
+   if( 0 <= drive
+    && drive <= 32
+       )
+   {
+     return( _get_fat_size( drive ) == 32 );
+   }
+ 
+   /* Drives that don't exist can't be FAT32. */
+   return( 0 );
+ }
Index: djgpp/src/libc/dos/dos/isfat32.txh
===================================================================
RCS file: isfat32.txh
diff -N isfat32.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- isfat32.txh	Sat Jun 10 08:51:24 2000
***************
*** 0 ****
--- 1,55 ----
+ @ignore
+  * Copyright (C) 2000 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
Index: djgpp/src/libc/dos/dos/isramdri.c
===================================================================
RCS file: isramdri.c
diff -N isramdri.c
*** /dev/null	Tue May  5 16:32:27 1998
--- isramdri.c	Sat Jun 10 08:51:25 2000
***************
*** 0 ****
--- 1,46 ----
+ /* 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
+ 
+ /*
+ 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.  
+ 
+ Return Value: 
+ 1 if the drive is a RAM drive, otherwise 0.  
+ */
+ 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;
+ }
Index: djgpp/src/libc/dos/dos/isramdri.txh
===================================================================
RCS file: isramdri.txh
diff -N isramdri.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- isramdri.txh	Sat Jun 10 08:51:25 2000
***************
*** 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
Index: djgpp/src/libc/dos/dos/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/dos/makefile,v
retrieving revision 1.1
diff -p -3 -r1.1 makefile
*** makefile	1995/06/18 05:50:38	1.1
--- makefile	2000/06/10 12:51:25
*************** SRC += getdate.c
*** 10,15 ****
--- 10,17 ----
  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
*************** SRC += int86.c
*** 17,22 ****
--- 19,28 ----
  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
Index: djgpp/src/libc/dos/dos/mediatyp.c
===================================================================
RCS file: mediatyp.c
diff -N mediatyp.c
*** /dev/null	Tue May  5 16:32:27 1998
--- mediatyp.c	Sat Jun 10 08:51:25 2000
***************
*** 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 */
+ }
Index: djgpp/src/libc/dos/dos/mediatyp.txh
===================================================================
RCS file: mediatyp.txh
diff -N mediatyp.txh
*** /dev/null	Tue May  5 16:32:27 1998
--- mediatyp.txh	Sat Jun 10 08:51:25 2000
***************
*** 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
Index: djgpp/src/libc/dos/io/_creat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/_creat.c,v
retrieving revision 1.3
diff -p -3 -r1.3 _creat.c
*** _creat.c	1996/08/31 22:09:32	1.3
--- _creat.c	2000/06/10 12:51:26
***************
*** 6,11 ****
--- 6,12 ----
  #include <go32.h>
  #include <dpmi.h>
  #include <io.h>
+ #include <dos.h>
  #include <libc/dosio.h>
  #include <sys/fsext.h>
  
*************** _creat(const char* filename, int attrib)
*** 25,42 ****
    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.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;
    __dpmi_int(0x21, &r);
    if(r.x.flags & 1)
    {
--- 26,51 ----
    if (__FSEXT_call_open_handlers(__FSEXT_creat, &rv, &filename))
      return rv;
  
    if(use_lfn) {
      r.x.ax = 0x716c;
!     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). It
+        seems it has a bug which only lets you create these big files
+        if LFN is enabled. */
+     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)
    {
Index: djgpp/src/libc/dos/io/_creat.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/_creat.txh,v
retrieving revision 1.3
diff -p -3 -r1.3 _creat.txh
*** _creat.txh	1999/06/20 08:53:34	1.3
--- _creat.txh	2000/06/10 12:51:26
*************** int _creat(const char *path, int attrib)
*** 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}).
  
  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.
  
  @subheading Return Value
  
--- 10,32 ----
  @subheading Description
  
  This is a direct connection to the MS-DOS creat function call, int 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 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
  
Index: djgpp/src/libc/dos/io/_creat_n.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/_creat_n.c,v
retrieving revision 1.1
diff -p -3 -r1.1 _creat_n.c
*** _creat_n.c	1998/06/28 22:42:16	1.1
--- _creat_n.c	2000/06/10 12:51:26
*************** _creatnew(const char* filename, int attr
*** 27,32 ****
--- 27,36 ----
  
    _put_path(filename);
    r.x.bx =
+     0x1000 |                   /* FAT32 extended size. */
+     /* FAT32 extended size flag doesn't help on WINDOZE 4.1 (98). It
+        seems it has a bug which only lets you create these big files
+        if LFN is enabled. */
      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;
Index: djgpp/src/libc/dos/io/_open.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/_open.c,v
retrieving revision 1.2
diff -p -3 -r1.2 _open.c
*** _open.c	1996/08/31 21:09:32	1.2
--- _open.c	2000/06/10 12:51:26
***************
*** 7,12 ****
--- 7,13 ----
  #include <go32.h>
  #include <dpmi.h>
  #include <io.h>
+ #include <dos.h>
  #include <libc/dosio.h>
  #include <sys/fsext.h>
  
*************** _open(const char* filename, int oflag)
*** 26,37 ****
    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.dx = 1;			/* Open existing file */
      r.x.si = __tb_offset;
    } else {
      r.h.ah = 0x3d;
      r.h.al = oflag;
--- 27,45 ----
    if (__FSEXT_call_open_handlers(__FSEXT_open, &rv, &filename))
      return rv;
  
    if(use_lfn) {
      r.x.ax = 0x716c;
!     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). It
+        seems it has a bug which only lets you create these big files
+        if LFN is enabled. */
+     r.x.dx = 1;                        /* Open existing file */
+     r.x.si = __tb_offset;
    } else {
      r.h.ah = 0x3d;
      r.h.al = oflag;
*************** _open(const char* filename, int oflag)
*** 39,44 ****
--- 47,53 ----
    }
    r.x.cx = 0;
    r.x.ds = __tb_segment;
+   _put_path(filename);
    __dpmi_int(0x21, &r);
    if(r.x.flags & 1)
    {
Index: djgpp/src/libc/dos/io/_open.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/_open.txh,v
retrieving revision 1.3
diff -p -3 -r1.3 _open.txh
*** _open.txh	1999/06/20 08:53:34	1.3
--- _open.txh	2000/06/10 12:51:26
*************** int _open(const char *path, int attrib);
*** 10,17 ****
  @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.
  
  This function can be hooked by the @dfn{File System Extensions}
  (@pxref{File System Extensions}).  If you don't want this, you should
--- 10,25 ----
  @subheading Description
  
  This is a direct connection to the MS-DOS open function call, int 0x21,
! %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
Index: djgpp/src/libc/posix/sys/stat/xstat.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/sys/stat/xstat.c,v
retrieving revision 1.1
diff -p -3 -r1.1 xstat.c
*** xstat.c	1996/01/24 03:30:20	1.1
--- xstat.c	2000/06/10 12:51:29
*************** _invent_inode(const char *name, unsigned
*** 159,183 ****
  {
    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.
     */
!   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);
  
    struct name_list  *name_ptr, *prev_ptr;
    const char        *p;
--- 159,174 ----
  {
    static struct name_list  *name_list[256];
  
!   /* 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. 
     */
! #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 = INVENTED_INODE_START;
  
    struct name_list  *name_ptr, *prev_ptr;
    const char        *p;
*************** _invent_inode(const char *name, unsigned
*** 187,193 ****
    if (xstat_count != __bss_count)
      {
        xstat_count = __bss_count;
!       inode_count = (sizeof(ino_t) > 2 ? (long)USHRT_MAX + 1L : USHRT_MAX);
        memset (name_list, 0, sizeof name_list);
      }
  
--- 178,184 ----
    if (xstat_count != __bss_count)
      {
        xstat_count = __bss_count;
!       inode_count = INVENTED_INODE_START;
        memset (name_list, 0, sizeof name_list);
      }
  
*************** _invent_inode(const char *name, unsigned
*** 219,225 ****
      {
        ino_t retval = inode_count;
  
!       inode_count += dir;
        return retval;
      }
  
--- 210,216 ----
      {
        ino_t retval = inode_count;
  
!       inode_count++;
        return retval;
      }
  
*************** _invent_inode(const char *name, unsigned
*** 270,276 ****
        else
          name_list[hash] = name_ptr;
        retval = inode_count;
!       inode_count += dir; /* increment or decrement as appropriate */
  
        return retval;
      }
--- 261,267 ----
        else
          name_list[hash] = name_ptr;
        retval = inode_count;
!       inode_count++; /* Increment for next call. */
  
        return retval;
      }
Index: djgpp/tests/libc/dos/dos/getfatsz.c
===================================================================
RCS file: getfatsz.c
diff -N getfatsz.c
*** /dev/null	Tue May  5 16:32:27 1998
--- getfatsz.c	Sat Jun 10 08:51:37 2000
***************
*** 0 ****
--- 1,35 ----
+ /*
+  * File getfatsz.c.
+  *
+  * Copyright (C) 2000 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 <stdio.h>
+ #include <dos.h>
+ 
+ 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);
+   }
+ 
+ }
Index: djgpp/tests/libc/dos/dos/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/dos/dos/makefile,v
retrieving revision 1.1
diff -p -3 -r1.1 makefile
*** makefile	1995/11/18 21:33:04	1.1
--- makefile	2000/06/10 12:51:37
***************
*** 1,5 ****
--- 1,6 ----
  TOP=../..
  
+ SRC += getfatsz.c
  SRC += i86.c
  SRC += srchpath.c
  SRC += tn.c

- Raw text -


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