From: Martin Str|mberg Message-Id: <199902201452.PAA19233@father.ludd.luth.se> Subject: FAT32 To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS) Date: Sat, 20 Feb 1999 15:52:43 +0100 (MET) X-Mailer: ELM [version 2.4ME+ PL15 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Reply-To: djgpp-workers AT delorie DOT com Here's the complete patch, including corrections as Eli suggested. New Model Army, The Love of Hopeless Causes, MartinS diff -ruN src.org/libc/compat/mntent/mntent.c src/libc/compat/mntent/mntent.c --- src.org/libc/compat/mntent/mntent.c Sun Nov 15 14:20:56 1998 +++ src/libc/compat/mntent/mntent.c Sun Jan 17 21:51:34 1999 @@ -368,26 +368,6 @@ } /* - * Return 1 if this drive is a CD-ROM drive, 0 otherwise. Works - * with MSCDEX 2.x, but what about other CD-ROM device drivers? - */ -static int -is_cdrom_drive(int drive_num) -{ - __dpmi_regs r; - - r.x.ax = 0x150b; /* CD-ROM Drive Check function */ - r.x.cx = drive_num - 1; /* 0 = A: */ - __dpmi_int(0x2f, &r); - - /* If MSCDEX installed, BX will hold ADADh; AX will be non-zero - if this drive is supported by MSCDEX. */ - if (r.x.bx == 0xadad && r.x.ax != 0) - return 1; - return 0; -} - -/* * Return 1 if a CD-ROM drive DRIVE_NUM is ready, i.e. there * is a disk in the drive and the tray door is closed. */ @@ -445,51 +425,6 @@ return 0; } -/* - * Detect a RAM disk. We do this by checking if the number of FAT - * copies (in the Device Parameter Block) is 1, which is typical of - * RAM disks. [This doesn't _have_ to be so, but if it's good - * enough for Andrew Schulman et al (Undocumented DOS, 2nd edition), - * we can use this as well.] - */ -static int -is_ram_drive(int drive_num) -{ - __dpmi_regs r; - - r.h.ah = 0x32; /* Get Device Parameter Block function */ - r.h.dl = drive_num; - __dpmi_int(0x21, &r); - - if (r.h.al == 0) - { - /* The pointer to DPB is in DS:BX. The number of FAT copies is at - offset 8 in the DPB. */ - char fat_copies = _farpeekb(dos_mem_base, MK_FOFF(r.x.ds, r.x.bx) + 8); - - return fat_copies == 1; - } - return 0; -} - -/* - * Check if the media in this disk drive is fixed or removable. - * Should only be called after we're sure this ain't CD-ROM or - * RAM disk, since these might fool you with this call. - */ -static int -media_type(int drive_num) -{ - __dpmi_regs r; - - r.x.ax = 0x4408; - r.h.bl = drive_num; - __dpmi_int(0x21, &r); - - if (r.x.flags & 1) - return -1; - return r.x.ax; /* returns 1 for fixed disks, 0 for removable */ -} /* Exported library functions. */ @@ -700,11 +635,11 @@ */ if (mnt_type[0] == '?') { - int disk_type = media_type(drive_number); + int disk_type = _media_type(drive_number); - if (is_ram_drive(drive_number)) + if (_is_ram_drive(drive_number)) mnt_type = NAME_ram; - else if (is_cdrom_drive(drive_number)) + else if (_is_cdrom_drive(drive_number)) { /* Empty CD-ROM drives do NOT fail _truename(), so we must see if there is a disk in the drive. */ diff -ruN src.org/libc/compat/sys/vfs/statfs.c src/libc/compat/sys/vfs/statfs.c --- src.org/libc/compat/sys/vfs/statfs.c Sun Dec 13 13:09:46 1998 +++ src/libc/compat/sys/vfs/statfs.c Sat Jan 16 19:00:58 1999 @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -17,7 +18,9 @@ __dpmi_regs regs; int drive_number; int cdrom_calls_used = 0; - int blocks = 0; + long blocks = 0; + long free = 0; + long bsize = 0; /* Get the drive number, including the case of magic names like /dev/c/foo. */ @@ -44,7 +47,7 @@ if ((regs.x.flags & 1) == 0 && regs.x.bx == 0xadad && regs.x.ax != 0) { unsigned char request_header[0x14]; - int status, i = 2, bsize = 0; + int status, i = 2; /* Construct the request header for the CD-ROM device driver. */ memset (request_header, 0, sizeof request_header); @@ -89,9 +92,8 @@ if (_farpeekw (_dos_ds, __tb + 8) == 0x100 && _farpeekw (_dos_ds, __tb + 5 + 0x12) == 5) { - regs.x.ax = 1; /* fake: sectors per cluster */ - regs.x.cx = bsize; - regs.x.bx = 0; /* no free space: cannot add data to CD-ROM */ + /* bsize has been set some lines above. */ + free = 0; /* no free space: cannot add data to CD-ROM */ blocks = _farpeekl (_dos_ds, __tb + 1); cdrom_calls_used = 1; } @@ -100,26 +102,70 @@ if (!cdrom_calls_used) { - /* Get free space info from DOS. */ - regs.h.ah = 0x36; /* DOS Get Free Disk Space call */ - regs.h.dl = drive_number + 1; - __dpmi_int(0x21, ®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? */ + && blocks <= free /* Has free maxed out? */ + ) { - errno = ENODEV; - return -1; + /* Get free space info from Extended Drive Parameter Block. */ + regs.x.ax = 0x7302; + regs.h.dl = drive_number + 1; + regs.x.es = __tb_segment; + regs.x.di = __tb_offset; + regs.x.cx = 0x100; /* 256 bytes should be enough (RBIL says 0x3f). */ + __dpmi_int(0x21, ®s); + + /* Errors? */ + if( regs.x.flags & 1 ) + { + errno = ENODEV; + return( -1 ); + } + + bsize = _farpeekw (_dos_ds, __tb + 0x2 + 0x2) * + ( _farpeekb (_dos_ds, __tb + 0x2 + 0x4) + 1 ); + free = _farpeekw (_dos_ds, __tb + 0x2 + 0x1f) + + 65536 * _farpeekw (_dos_ds, __tb + 0x2 + 0x21); + blocks = _farpeekl( _dos_ds, __tb + 0x2 + 0x2d); +#if 0 + printf("Second: bsize = %ld, free = %ld, blocks = %ld.\n" + , bsize + , free + , blocks + ); +#endif + } - blocks = regs.x.dx; } /* Fill in the structure */ - buf->f_bavail = regs.x.bx; - buf->f_bfree = regs.x.bx; + buf->f_bavail = free; + buf->f_bfree = free; buf->f_blocks = blocks; - buf->f_bsize = regs.x.cx * regs.x.ax; - buf->f_ffree = regs.x.bx; + buf->f_bsize = bsize; + buf->f_ffree = free; buf->f_files = blocks; buf->f_type = 0; buf->f_fsid[0] = drive_number; diff -ruN src.org/libc/compat/unistd/_llseek.c src/libc/compat/unistd/_llseek.c --- src.org/libc/compat/unistd/_llseek.c Thu Jan 1 00:00:00 1970 +++ src/libc/compat/unistd/_llseek.c Sat Feb 6 14:24:28 1999 @@ -0,0 +1,128 @@ +/* + * File _llseek.c. + * + * Copyright (C) 1999 Martin Str”mberg . + * + * This software may be used freely so long as this copyright notice is + * left intact. There is no warranty on this software. + * + */ + +#include +#include +#include + +#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 + +offset_t _llseek(int fd, offset_t offset, int whence); +@end example + +@subheading Description + +This function moves the file pointer for @var{fd} according to +@var{whence}: + +@table @code + +@item SEEK_SET + +The file pointer is moved to the offset specified. + +@item SEEK_CUR + +The file pointer is moved relative to its current position. + +@item SEEK_END + +The file pointer is moved to a position @var{offset} bytes from the end +of the file. The offset is usually nonpositive in this case. + +@end table + +@var{offset} is of type long long, thus enabling you to seek with +offsets as large as ~2^63. + +@subheading Return Value + +The new offset is returned. Note that due to limitations in the +underlying DOS implementation only return values in the range +[0, MAX_INT] should be relied upon. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +long long ret; + +ret = _llseek(fd, (1<<32), SEEK_SET); /* Now ret equals 0 (unfortunately). */ +ret = _llseek(fd, -1, SEEK_CUR); /* Now ret equals 2^32-1 (good!). */ +ret = _llseek(fd, 0, SEEK_SET); /* Now ret equals 0 (good!). */ +ret = _llseek(fd, -1, SEEK_CUR); /* Now ret equals 2^32-1 (bad). */ +@end example + diff -ruN src.org/libc/compat/unistd/makefile src/libc/compat/unistd/makefile --- src.org/libc/compat/unistd/makefile Sun Jun 28 21:53:24 1998 +++ src/libc/compat/unistd/makefile Sat Feb 6 00:16:44 1999 @@ -2,6 +2,7 @@ # Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details TOP=../.. +SRC += _llseek.c SRC += basename.c SRC += dirname.c SRC += fsync.c diff -ruN src.org/libc/dos/dos/getfatsz.c src/libc/dos/dos/getfatsz.c --- src.org/libc/dos/dos/getfatsz.c Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/getfatsz.c Sat Jan 9 13:29:48 1999 @@ -0,0 +1,38 @@ +/* + * File getfatsz.c. + * + * Copyright (C) 1999 Martin Str”mberg . + * + * This software may be used freely so long as this copyright notice is + * left intact. There is no warranty on this software. + * + */ + +#include +#include + +/* Returns number of bits in FAT; 0 == FAT of unknown size; -1 == error. */ +int +_get_fat_size( const int drive /* drive number (1=A:). */ + ) +{ + char s[9]; + int n; + int size; + + if( _get_fs_type( drive, s ) ) + { + if( s[0] == 'F' && s[1] == 'A' && s[2] == 'T' ) + { + size = 0; + for(n = 3; n < 8 && ( '0' <= s[n] && s[n] <= '9' ); n++) + { + size = 10*size + s[n] - '0'; + } + + return( size ); + } + } + + return( -1 ); +} diff -ruN src.org/libc/dos/dos/getfatsz.txh src/libc/dos/dos/getfatsz.txh --- src.org/libc/dos/dos/getfatsz.txh Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/getfatsz.txh Sun Jan 10 19:00:42 1999 @@ -0,0 +1,47 @@ +@node _get_fat_size, file system +@subheading Syntax + +@example +#include + +int _get_fat_size( const int drive ); +@end example + +@subheading Description + +This function tries to determine the number bits used to enumerate the +clusters by the FAT on drive number @var{drive}. 1 == A:, 2 == B:, +etc. + +This function will not succeed on DOS version < 4. + +@subheading Return Value + +The number of bits used by the FAT (12, 16 or 32). 0 if the drive was +formatted with FAT but of unknown size (NT reports that on FAT16). -1 +on error. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +#include +#include + +int main(void) +@{ + int size; + + size = _get_fs_type( 'C' - 'A' + 1 ); + if( 0 <= size ) + @{ + printf("The size of FAT on C: is %d bits.\n", size); + @} + + exit(0); +@} + +@end example diff -ruN src.org/libc/dos/dos/getfstyp.c src/libc/dos/dos/getfstyp.c --- src.org/libc/dos/dos/getfstyp.c Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/getfstyp.c Sat Jan 9 13:29:04 1999 @@ -0,0 +1,58 @@ +/* + * File getfstyp.c. + * + * Copyright (C) 1999 Martin Str”mberg . + * + * This software may be used freely so long as this copyright notice is + * left intact. There is no warranty on this software. + * + */ + +#include +#include +#include +#include + +/* Returns: 0 == error; 1 == result_str filled in. */ +int +_get_fs_type( const int drive /* drive number (1=A:). */ + , char *const result_str /* String to put result in. At least 9 chars long. */ + ) +{ + int n; + __dpmi_regs r; + + /* Check DOZE version and return -1 if too low. */ + if( ( _get_dos_version(1) >> 8) < 4 ) + { + return( 0 ); + } + + /* Call INT21, ax==0x6900 i.e. Get Disk Serial Number (sic!). */ + r.x.ax = 0x6900; + r.h.bl = drive; + r.h.bh = 0; + r.x.ds = __tb >> 4; + r.x.dx = __tb & 0x0f; + __dpmi_int(0x21, &r); + if( (r.x.flags & 1) == 0 ) + { + /* Get the file system type. */ + for(n = 0; n < 8; n++) + { + result_str[n] = _farpeekb( _dos_ds, __tb + 0x11 + n); + } + result_str[8] = 0; + + /* Remove terminating spaces. */ + for(n = 7; n && result_str[n] == ' '; n-- ) + { + result_str[n] = 0; + } + + return( 1 ); + } + + return( 0 ); + +} diff -ruN src.org/libc/dos/dos/getfstyp.txh src/libc/dos/dos/getfstyp.txh --- src.org/libc/dos/dos/getfstyp.txh Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/getfstyp.txh Sun Jan 10 19:00:46 1999 @@ -0,0 +1,48 @@ +@node _get_fs_type, file system +@subheading Syntax + +@example +#include + +int _get_fs_type( const int drive + , char *const result_str + ); +@end example + +@subheading Description + +This function tries to extract the file system type of the drive +number @var{drive}, 1 == A:, 2 == B:, etc. If successful the result +is put in @var{result_str} which must be at least 9 characters long. + +This function will not succeed on DOS version < 4 and is known to have +trouble detecting the file system type of disks formatted with a later +version of DOS than on the version it is run on. + +@subheading Return Value + +1 if the file system type was extracted successfully; otherwise 0. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +#include +#include + +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 */ + +#include +#include + +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 + +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 +#include + +int main(void) +@{ + + if( _is_cdrom_drive( 'R' - 'A' + 1 ) ) + @{ + printf("C: is a CDROM drive.\n"); + @} + else + @{ + printf("C: is not a CDROM drive.\n"); + @} + + exit(0); +@} + +@end example diff -ruN src.org/libc/dos/dos/isfat32.c src/libc/dos/dos/isfat32.c --- src.org/libc/dos/dos/isfat32.c Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/isfat32.c Sun Jan 17 21:11:56 1999 @@ -0,0 +1,76 @@ +/* + * This is the file isfat32.c. + * + * Copyright (C) 1999 Martin Str”mberg . + * + * This software may be used freely so long as this copyright notice is + * left intact. There is no warranty on this software. + * + */ + +#include + +static unsigned long checked = 0; +static unsigned long removable = 0; +static unsigned long fat32 = 0; + +/* Returns 1 if the drive is formatted with FAT32; 0 otherwise. */ +int +_is_fat32( const int drive /* drive number (1=A:). */ + ) +{ + unsigned long mask; + + /* Check input. */ + if( 0 <= drive + && drive <= 32 + ) + { + /* Always check current drive (as we don't know if it's been changed). */ + if( drive == 0 ) + { + return( _get_fat_size( drive ) == 32 ); + } + else + { + mask = 1 << ( drive - 1 ); + + /* Have we checked this drive for FAT32 yet and it isn't removable? */ + if( checked & mask + && !( removable & mask ) ) + { + return( ( fat32 & mask ) != 0 ); + } + + /* Always recheck removable drives. */ + if( removable & mask ) + { + return( _get_fat_size( drive ) == 32 ); + } + + /* Previously untested drive -> update tables. */ + + /* Is this a removable drive? (!_is_*_drive for _media_type problems.) */ + if( !_is_ram_drive( drive ) + && !_is_cdrom_drive( drive ) + && _media_type( drive ) == 0 ) + { + removable |= mask; + checked |= mask; + return( _get_fat_size( drive ) == 32 ); + } + + if( _get_fat_size( drive ) == 32 ) + { + fat32 |= mask; + } + + checked |= mask; + + return( ( fat32 & mask ) != 0 ); + } + } + + /* Drives that don't exist can't be FAT32. */ + return( 0 ); +} diff -ruN src.org/libc/dos/dos/isfat32.txh src/libc/dos/dos/isfat32.txh --- src.org/libc/dos/dos/isfat32.txh Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/isfat32.txh Sun Jan 17 21:04:52 1999 @@ -0,0 +1,47 @@ +@node _is_fat32, file system +@subheading Syntax + +@example +#include + +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 +#include + +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 */ + +#include +#include +#include +#include + +/* Macro to convert a segment and an offset to a "far offset" suitable + for _farxxx() functions of DJGPP. */ +#ifndef MK_FOFF +#define MK_FOFF(s,o) ((int)((((unsigned long)(unsigned short)(s)) << 4) + \ + (unsigned short)(o))) +#endif + +int +_is_ram_drive(int drive_num) +{ + __dpmi_regs r; + + r.h.ah = 0x32; /* Get Device Parameter Block function */ + r.h.dl = drive_num; + __dpmi_int(0x21, &r); + + if (r.h.al == 0) + { + /* The pointer to DPB is in DS:BX. The number of FAT copies is at + offset 8 in the DPB. */ + char fat_copies = _farpeekb(_dos_ds, MK_FOFF(r.x.ds, r.x.bx) + 8); + + return fat_copies == 1; + } + return 0; +} diff -ruN src.org/libc/dos/dos/isramdri.txh src/libc/dos/dos/isramdri.txh --- src.org/libc/dos/dos/isramdri.txh Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/isramdri.txh Sun Jan 17 19:57:46 1999 @@ -0,0 +1,37 @@ +@node _is_ram_drive, file system +@subheading Syntax + +@example +#include + +int _is_ram_drive( const int drive ); +@end example + +@subheading Description + +This function checks if drive number @var{drive} (1 == A:, 2 == B:, +etc.) is a RAM disk. It is done by checking if the number of FAT +copies (in the Device Parameter Block) is 1, which is typical of +RAM disks. (This doesn't _have_ to be so, but if it's good enough for +Andrew Schulman et al (Undocumented DOS, 2nd edition), we can use this +as well.) + +@subheading Return Value + +1 if the drive is a RAM drive, otherwise 0. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +#include +#include + + 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 */ + +#include +#include + +int +_media_type(int drive_num) +{ + __dpmi_regs r; + + r.x.ax = 0x4408; + r.h.bl = drive_num; + __dpmi_int(0x21, &r); + + if (r.x.flags & 1) + return -1; + return r.x.ax; /* returns 1 for fixed disks, 0 for removable */ +} diff -ruN src.org/libc/dos/dos/mediatyp.txh src/libc/dos/dos/mediatyp.txh --- src.org/libc/dos/dos/mediatyp.txh Thu Jan 1 00:00:00 1970 +++ src/libc/dos/dos/mediatyp.txh Sun Jan 17 18:47:42 1999 @@ -0,0 +1,53 @@ +@node _media_type, file system +@subheading Syntax + +@example +#include + +int _media_type( const int drive ); +@end example + +@subheading Description + +This function checks if drive number @var{drive} (. 1 == A:, 2 == B:, +etc.) is fixed or removable. + +@code{_media_type} should only be called after you are sure the drive +isn't a CD-ROM or a RAM disk, since these might fool you with this +call. + +For performance reasons the result is cached. + +@subheading Return Value + +1 if the drive is a fixed disk, 0 if it is removable. -1 on error. + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +#include +#include + +Some work is needed here. + + +int main(void) +@{ + + if( _is_fat32( 'C' - 'A' + 1 ) ) + @{ + printf("C: is a FAT32 drive.\n"); + @} + else + @{ + printf("C: is not a FAT32 drive.\n"); + @} + + exit(0); +@} + +@end example diff -ruN src.org/libc/dos/io/_creat.c src/libc/dos/io/_creat.c --- src.org/libc/dos/io/_creat.c Sat Aug 31 22:09:32 1996 +++ src/libc/dos/io/_creat.c Sun Jan 31 16:12:50 1999 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -26,12 +27,17 @@ if (__FSEXT_call_open_handlers(__FSEXT_open, &rv, &filename)) return rv; - _put_path(filename); if(use_lfn) { r.x.ax = 0x716c; - r.x.bx = oflag & 0xff; + r.x.bx = (oflag & 0xff) | 0x1000; /* 0x1000 is FAT32 extended size. */ r.x.dx = 1; /* Open existing file */ r.x.si = __tb_offset; + } else if(7 <= (_get_dos_version(1) >> 8)) { + r.x.ax = 0x6c00; + r.x.bx = (oflag & 0xff) | 0x1000; /* 0x1000 is FAT32 extended size. */ + /* FAT32 extended size flag doesn't help on WINDOZE 4.1 (98). */ + r.x.dx = 1; /* Open existing file */ + r.x.si = __tb_offset; } else { r.h.ah = 0x3d; r.h.al = oflag; @@ -39,6 +45,7 @@ } r.x.cx = 0; r.x.ds = __tb_segment; + _put_path(filename); __dpmi_int(0x21, &r); if(r.x.flags & 1) { diff -ruN src.org/libc/dos/io/_open.txh src/libc/dos/io/_open.txh --- src.org/libc/dos/io/_open.txh Sun Sep 27 15:21:32 1998 +++ src/libc/dos/io/_open.txh Sun Jan 31 20:54:48 1999 @@ -10,12 +10,21 @@ @subheading Description This is a direct connection to the MS-DOS open function call, int 0x21, -%ah = 0x3d. (When long file names are supported, @code{_open} calls -function 0x716c of Int 0x21.) The file is set to binary mode. +%ah = 0x3d, on versions of DOS earlier than 7.0. On DOS version 7.0 or +later @code{_open} calls function int 0x21, %ax = 0x6c00. When long +file names are supported, @code{_open} calls function 0x716c of int +0x21. -This function can be hooked by the @xref{File System Extensions}. If -you don't want this you should use @xref{_dos_open} (but note that the -latter doesn't support long file names). +On FAT32 file systems file size bigger than ~2^31 is supported. Note +that WINDOWS 98 has a bug which only lets you create these big files +if LFN is enabled. In plain DOS mode it plainly works. + +The file is set to binary mode. + +This function can be hooked by the File System Extensions (@pxref{File +System Extensions}. If you don't want this you should use +@code{_dos_open} (but note that the latter doesn't support long file +names). @subheading Return Value diff -ruN src.org/libc/posix/sys/stat/xstat.c src/libc/posix/sys/stat/xstat.c --- src.org/libc/posix/sys/stat/xstat.c Tue Jan 23 22:30:20 1996 +++ src/libc/posix/sys/stat/xstat.c Mon Feb 1 23:47:34 1999 @@ -159,25 +159,17 @@ { static struct name_list *name_list[256]; - /* If the st_inode is wider than a short int, we will count up - * from USHRT_MAX+1 and thus ensure there will be no clashes with - * actual cluster numbers. - * Otherwise, we must count downward from USHRT_MAX, which could - * yield two files with identical inode numbers: one from actual - * DOS cluster number, and another from this function. In the - * latter case, we still have at least 80 inode numbers before - * we step into potentially used numbers, because some FAT entries - * are reserved to mean EOF, unused entry and other special codes, - * and the FAT itself uses up some clusters which aren't counted. + /* We count downward from INT_MAX, which can't yield two files with + * identical inode numbers: FAT16 uses maximum ~2^16 and FAT32 uses + * maximum ~2^28. So in the worst case we have at least INT_MAX - + * 2^28 invented cluster numbers. When this is written this equals + * 2^31 - 2^28, which is > 2^30. */ - static int dir = (sizeof(ino_t) > 2 ? 1 : -1); /* INODE_COUNT is declared LONG and not ino_t, because some DOS-based * compilers use short or unsigned short for ino_t. */ - static long inode_count = (sizeof(ino_t) > 2 - ? (long)USHRT_MAX + 1L - : USHRT_MAX); + static long inode_count = INT_MAX; struct name_list *name_ptr, *prev_ptr; const char *p; @@ -187,7 +179,7 @@ if (xstat_count != __bss_count) { xstat_count = __bss_count; - inode_count = (sizeof(ino_t) > 2 ? (long)USHRT_MAX + 1L : USHRT_MAX); + inode_count = INT_MAX; memset (name_list, 0, sizeof name_list); } @@ -219,7 +211,7 @@ { ino_t retval = inode_count; - inode_count += dir; + inode_count--; return retval; } @@ -270,7 +262,7 @@ else name_list[hash] = name_ptr; retval = inode_count; - inode_count += dir; /* increment or decrement as appropriate */ + inode_count--; /* Decrement for next call. */ return retval; } diff -ruN include.org/dos.h include/dos.h --- include.org/dos.h Mon Sep 7 18:55:40 1998 +++ include/dos.h Tue Jan 19 21:08:06 1999 @@ -134,6 +134,12 @@ unsigned short _get_dos_version(int); +int _get_fat_size(const int drive); +int _get_fs_type(const int drive, char *const result_str); +int _is_cdrom_drive(const int drive); +int _is_fat32(const int drive); +int _is_ram_drive(const int drive); +int _media_type(const int drive); int int86(int ivec, union REGS *in, union REGS *out); int int86x(int ivec, union REGS *in, union REGS *out, struct SREGS *seg); diff -ruN include.org/sys/djtypes.h include/sys/djtypes.h --- include.org/sys/djtypes.h Wed Sep 9 16:56:26 1998 +++ include/sys/djtypes.h Fri Feb 5 23:42:46 1999 @@ -6,6 +6,7 @@ #define __DJ_clock_t typedef int clock_t; #define __DJ_gid_t typedef int gid_t; #define __DJ_off_t typedef int off_t; +#define __DJ_offset_t typedef long long offset_t; #define __DJ_pid_t typedef int pid_t; #define __DJ_size_t typedef long unsigned int size_t; #define __DJ_ssize_t typedef int ssize_t; diff -ruN include.org/sys/types.h include/sys/types.h --- include.org/sys/types.h Sat Feb 22 13:06:06 1997 +++ include/sys/types.h Fri Feb 5 23:42:52 1999 @@ -24,6 +24,9 @@ __DJ_off_t #undef __DJ_off_t #define __DJ_off_t +__DJ_offset_t +#undef __DJ_offset_t +#define __DJ_offset_t __DJ_pid_t #undef __DJ_pid_t #define __DJ_pid_t diff -ruN include.org/unistd.h include/unistd.h --- include.org/unistd.h Mon Jun 29 00:02:48 1998 +++ include/unistd.h Fri Feb 5 23:44:40 1999 @@ -72,6 +72,7 @@ void __exit(int _status) __attribute__((noreturn)); void _exit(int _status) __attribute__((noreturn)); +offset_t _llseek(int _fildes, offset_t _offset, int _whence); int access(const char *_path, int _amode); unsigned int alarm(unsigned int _seconds); int chdir(const char *_path);