#include #include typedef struct BPB { char bootcode[3]; char oem_string[8]; unsigned short bytes_per_sector; unsigned char sectors_per_cluster; unsigned short reserved_sector_count; unsigned char table_count; unsigned short root_entry_count; unsigned short total_sectors; unsigned char media_type; unsigned short table_size; unsigned short sectors_per_track; unsigned short head_side_count; } __attribute__((packed)) BPB; typedef unsigned short Cluster; typedef struct Entry { char name[8]; char extension[3]; char res[15]; Cluster first_cluster; unsigned int size; } __attribute__((packed)) Entry; Cluster getEntry(unsigned char* fat, Cluster cluster) { int offset = cluster + (cluster /2); if (cluster % 2 == 0) { return fat[offset] | ((unsigned short) fat[offset+1] & 0xF) << 8; } else { return (fat[offset] >> 4) | ((unsigned short) fat[offset+1]) << 4; } } int dosNameToString(char* name, char* ext, char* string) { int pos = 0; for (int i = 0; i < 8; i++) { if (name[i] != 0x20) string[pos++] = name[i]; } string[pos++] = '.'; for (int i = 0; i < 3; i++) { if (ext[i] != 0x20) string[pos++] = ext[i]; } string[pos] = 0x00; return pos; } int main(int argc, char** argv) { FILE* image_file = fopen(argv[1], "rb"); BPB geo; int count; count = fread(&geo, sizeof(BPB), 1, image_file); if (count < 1) { printf("Failed to read BIOS Parameter Block\n"); return 1; } char oem[9]; for (int i = 0; i < 8; i++) { oem[i] = geo.oem_string[i]; } oem[8] = 0x00; printf("OEM: %s\n", oem); printf("Bytes per Sector: %hu\n", geo.bytes_per_sector); printf("Sectors per Cluster: %hhu\n", geo.sectors_per_cluster); printf("Reserved Sectors: %hu\n", geo.reserved_sector_count); printf("Table Count: %hhu\n", geo.table_count); printf("Root Entries: %hu\n", geo.root_entry_count); printf("Total Sectors: %hu\n", geo.total_sectors); printf("Sectors per Table: %hu\n", geo.table_size); printf("Sectors per Track: %hu\n", geo.sectors_per_track); printf("Head Count: %hu\n", geo.head_side_count); unsigned char* fat = (unsigned char*) malloc(geo.bytes_per_sector * geo.table_size); fseek(image_file, 0x200, SEEK_SET); count = fread(fat, geo.bytes_per_sector, geo.table_size, image_file); if (count < geo.table_size) { printf("Failed to read entire FAT\n"); return 1; } int root_offset = (1 + geo.table_size*geo.table_count) * geo.bytes_per_sector; int bytes_per_cluster = geo.bytes_per_sector * geo.sectors_per_cluster; int data_offset = (root_offset + (geo.root_entry_count * 32) + (bytes_per_cluster-1)) / bytes_per_cluster * bytes_per_cluster; printf("data start = %x\n", data_offset); int file_count = 0; Entry entry; fseek(image_file, root_offset, SEEK_SET); fread(&entry, sizeof(Entry), 1, image_file); char filename[13]; FILE* out_file; unsigned char* buffer = (unsigned char*) malloc(bytes_per_cluster); Cluster current; int bytes_copied; int grab; for (int i = 0; i < geo.root_entry_count; i++) { fseek(image_file, root_offset + 32*i, SEEK_SET); fread(&entry, sizeof(Entry), 1, image_file); if (entry.name[0] == 0x00 ) break; if (entry.name[0] != 0xE5) { file_count++; dosNameToString(entry.name, entry.extension, filename); printf("%14s %4hu %14u\n", filename, entry.first_cluster, entry.size); out_file = fopen(filename, "wb"); if (out_file == 0) { printf("Could not open '%s' for writing\n", filename); continue; } current = entry.first_cluster; bytes_copied = 0; while (bytes_copied < entry.size) { if (current >= 0xFF8 ) { printf("Not enough clusters!\n"); break; } int grab = (entry.size - bytes_copied > bytes_per_cluster) ? bytes_per_cluster : entry.size - bytes_copied; fseek(image_file, data_offset + (bytes_per_cluster*(current-2)), SEEK_SET); fread(buffer, 1, grab, image_file); fwrite(buffer, 1, grab, out_file); bytes_copied += grab; current = getEntry(fat, current); } fclose(out_file); } } printf("%d file(s)\n", file_count); free(buffer); free(fat); fclose(image_file); return 0; }