From: Martin Str|mberg Message-Id: <199909221647.SAA27177@father.ludd.luth.se> Subject: Re: FAT32 detection To: djgpp-workers AT delorie DOT com (DJGPP-WORKERS) Date: Wed, 22 Sep 1999 18:47:42 +0200 (MET DST) In-Reply-To: from Eli Zaretskii at "Sep 21, 99 02:53:40 pm" X-Mailer: ELM [version 2.4ME+ PL15 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk According to Eli Zaretskii: > I don't remember, it was a long time ago. Perhaps you could post an > augmented source, and I will then test. Ok, here it is. Right, MartinS /* * File getfatsz.c. * * Copyright (C) 1999 Martin Str<94>mberg . * * 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 . * */ #include #include #include #include #include #include #include #include #include #include #include /* 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 cha rs 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 ); } /* Returns number of bits in FAT; 0 == FAT of unknown size; -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; 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); } } 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 ) { /* The algorithm misdetects NTFS as FAT16, so lets check if it's NTFS. */ char tmp[9]; if( !_get_fs_type( drive, tmp ) && tmp[0] == 'N' && tmp[1] == 'T' ) { errno = ENOSYS; return( -1 ); } size = 16; } else { size = 32; } #if 0 fprintf(stderr, "bytes_per_sector = %ld.\n", bytes_per_sector); fprintf(stderr, "sectors_per_cluster = %ld.\n", sectors_per_cluster); fprintf(stderr, "reserved_sectors = %ld.\n", reserved_sectors); fprintf(stderr, "number_of_fats = %ld.\n", number_of_fats); fprintf(stderr, "root_entries = %ld.\n", root_entries); fprintf(stderr, "fat16_size = %ld.\n", fat16_size); fprintf(stderr, "fat32_size = %ld.\n", fat32_size); fprintf(stderr, "total16_sectors = %ld.\n", total16_sectors); fprintf(stderr, "total32_sectors = %ld.\n", total32_sectors); fprintf(stderr, "root_sectors = %ld.\n", root_sectors); fprintf(stderr, "data_sectors = %ld.\n", data_sectors); fprintf(stderr, "number_of_clusters = %ld.\n", number_of_clusters); #endif return( size ); } #if 1 int main(int argc, char *argv[]) { int ret; if( argc == 2 && 'A' <= argv[1][0] && argv[1][0] <= 'Z' ) { ret = _get_fat_size(argv[1][0] - 'A' + 1); fprintf(stderr, "_get_fat_size returned %d.\n", ret); return(0); } else { fprintf(stderr, "%s: run like this '%s C'.\n", argv[0], argv[0]); return(1); } } #endif