/***************************************************************************** checks for FAT- (DOS-) format disk, prints FAT info compiles with Turbo C, 16-bit Watcom C, or DJGPP This code is public domain (no copyright). You can do whatever you want with it. *****************************************************************************/ #include /* atoi() */ #include /* printf(), sscanf() */ #include /* _DISK_nnn, struct diskinfo_t, _bios_disk() */ /* these assume little-endian CPU like x86 */ #define LE16(X) *(uint16_t *)(X) #define LE32(X) *(uint32_t *)(X) /* #include these assume sizeof(short)==2 and sizeof(long)==4 */ typedef unsigned short uint16_t; typedef unsigned long uint32_t; /***************************************************************************** *****************************************************************************/ #if defined(__TURBOC__) #if __TURBOC__<0x0300 #define _DISK_RESET 0 #define _DISK_READ 2 struct diskinfo_t { unsigned drive, head, track, sector, nsectors; void far *buffer; }; int _bios_disk(int cmd, struct diskinfo_t *i) { return biosdisk(cmd, i->drive, i->head, i->track, i->sector, i->nsectors, (void *)i->buffer); } #endif #endif /***************************************************************************** *****************************************************************************/ static int read_sector(unsigned drive, unsigned cyl, unsigned head, unsigned sect, unsigned char *buf) { struct diskinfo_t cmd; unsigned tries, err; cmd.drive = drive; cmd.head = head; cmd.track = cyl; cmd.sector = sect; cmd.nsectors = 1; cmd.buffer = buf; for(tries = 3; tries != 0; tries--) { err = _bios_disk(_DISK_READ, &cmd); err >>= 8; if(err == 0) return 0; _bios_disk(_DISK_RESET, &cmd); } printf("error 0x%02X reading drive\n", err); return -1; } /***************************************************************************** *****************************************************************************/ static int lg2(unsigned arg) { unsigned log; for(log = 0; log < 16; log++) { if(arg & 1) { arg >>= 1; return (arg != 0) ? -1 : log; } arg >>= 1; } return -1; } /***************************************************************************** *****************************************************************************/ static int check_if_fat_bootsector(unsigned char *buf) { unsigned temp; int bad = 0; if(buf[0] == 0xE9) /* OK */; else if(buf[0] == 0xEB && buf[2] == 0x90) /* OK */; else { printf("Missing JMP/NOP\n"); bad = 1; } /* check other stuff */ temp = buf[13]; if(lg2(temp) < 0) { printf("Sectors per cluster (%u) is not a power of 2\n", temp); bad = 1; } temp = buf[16]; /* very few disks have only 1 FAT, but it's valid */ if(temp != 1 && temp != 2) { printf("Invalid number of FATs (%u)\n", temp); bad = 1; } temp = LE16(buf + 24); /* can't check against dev->sects because dev->sects may not yet be set */ if(temp == 0 || temp > 63) { printf("Invalid number of sectors (%u)\n", temp); bad = 1; } temp = LE16(buf + 26); /* can't check against dev->heads because dev->heads may not yet be set */ if(temp == 0 || temp > 255) { printf("Invalid number of heads (%u)\n", temp); bad = 1; } return bad; } /***************************************************************************** *****************************************************************************/ int main(int arg_c, char *arg_v[]) { unsigned num_fats, spc, bps, nre, fs, bs, rs; unsigned drive, part = 0; unsigned char buf[512]; unsigned long ts, ds; if(arg_c < 2) drive = 0; else { sscanf(arg_v[1], "%X", &drive); if(drive != 0 && drive != 1 && drive != 0x80 && drive != 0x81) { printf("Bad INT 13h drive number 0x%X " "(must be 0, 1, 0x80, or 0x81)\n", drive); return 1; } if(arg_c < 3) part = 0; else { part = atoi(arg_v[2]); if(part > 3) { printf("Bad primary partition number %u " "(must be < 4)\n", part); return 1; } } } if(drive >= 0x80) printf("partition %u on ", part); printf("drive 0x%02X:\n\n", drive); /* read floppy bootsector or hard disk MBR/partition table */ if(read_sector(drive, 0, 0, 1, buf) != 0) return 1; if(drive >= 0x80) { unsigned char *ptab_rec, head, sect; unsigned short cyl; /* point to partition table entry */ ptab_rec = buf + 446 + 16 * part; /* make sure it's FAT16 */ if(ptab_rec[4] != 6) goto NOT; /* get starting CHS of partition */ cyl = ptab_rec[3]; head = ptab_rec[1]; sect = ptab_rec[2] & 0x3F; if(ptab_rec[2] & 0x40) cyl |= 0x100; if(ptab_rec[2] & 0x80) cyl |= 0x200; /* read zeroth sector of partition (the hard disk bootsector) */ if(read_sector(drive, cyl, head, sect, buf) != 0) return 1; } if(check_if_fat_bootsector(buf)) NOT: { printf("not a FAT volume\n"); return 1; } bps = LE16(buf + 11); printf("Disk geometry:\n"); printf(" Bytes per sector = %u\n", bps); printf(" Number of heads = %u\n", LE16(buf + 26)); printf(" Sectors per track = %u\n", LE16(buf + 24)); /* */ spc = buf[13]; printf("FAT info:\n"); printf(" Sectors per cluster = %u\n", spc); num_fats = buf[16]; printf(" Number of FATs = %u\n", num_fats); nre = LE16(buf + 17); printf(" Number of root dir entries = %u\n", nre); fs = LE16(buf + 22); printf(" Sectors per FAT = %u\n", fs); fs *= num_fats; printf(" Number of hidden sectors = %lu (partition start)\n", LE32(buf + 28)); /* */ ts = LE16(buf + 19); if(ts == 0) ts = LE32(buf + 32); bs = LE16(buf + 14); rs = (nre * 32 + bps - 1) / bps; /* */ ds = ts - bs - rs - fs; while(ds % spc != 0) ds--; printf(" Total clusters = %lu ", ds / spc); if(ds / spc < 4085) printf("(FAT12)\n"); else if(ds / spc < 65525u) printf("(FAT16)\n"); else printf("(FAT32)\n"); printf(" Sectors: %u boot, %u root, %u FAT, %lu data, %lu wasted, " "%lu total\n\n", bs, /* reserved/boot sectors */ rs, /* root dir sectors */ fs, /* FAT sectors */ ds, /* data sectors */ ts - bs - rs - fs - ds, /* wasted sectors */ ts); /* total sectors */ return 0; }