Mail Archives: djgpp-workers/1999/03/14/05:14:29
Here is my latest version of FAT32 support. I'm pretty satisfied with
it, so now it's time to voice your opinions if you see something
wrong.
Pärt, Fratres,
MartinS
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);
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 Mar 13 23:35:08 1999
@@ -4,12 +4,14 @@
#include <string.h>
#include <dpmi.h>
#include <go32.h>
+#include <dos.h>
#include <libc/farptrgs.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/vfs.h>
#include <libc/dosio.h>
+#include <stdio.h>
int
statfs(const char *path, struct statfs *buf)
@@ -17,7 +19,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 +48,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 +93,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 +103,84 @@
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, ®s);
+ /* Get free space info from DOS. */
+ regs.h.ah = 0x36; /* DOS Get Free Disk Space call */
+ regs.h.dl = drive_number + 1;
+ __dpmi_int(0x21, ®s);
- /* Check for errors */
- if ((regs.x.ax & 0xffff) == 0xffff)
+ /* 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? */
+ )
{
- 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, ®s);
+
+ /* 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
+
}
- 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 Mar 13 18:16:20 1999
@@ -0,0 +1,39 @@
+/*
+ * 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 );
+ }
+ }
+
+ /* _get_fs_type() sets errno. */
+ 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 Sat Mar 13 18:16:20 1999
@@ -0,0 +1,53 @@
+@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 Sat Mar 13 18:16:18 1999
@@ -0,0 +1,53 @@
+@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 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 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 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 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 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;
}
- Raw text -