#include #include #include #include "fat12.h" #include "fat12-internals.h" #include "io.h" #include // Create a FAT12 filesystem using the given file descriptor, // with length _bytes_. // It will define a root directory size and padding size so that the file sectors // end up on 4096-byte boundaries. int fat12_mkfs(struct pang_io *io, uint32_t bytes) { uint8_t mbr[512]; off_t offset = 0; const uint32_t sector_size = 512; uint32_t cluster_size = 4096 / sector_size; // 4 kiB cluster sizes match flash erase block size if (bytes > 16000000) { // We run out of clusters just below 16 megabytes. Use bigger cluseters. cluster_size = 8192 / sector_size; } const uint32_t reserved_sectors = 1; // The MBR is the only reserved sector // XXX What happens if this is an even multiple of sectors? // Size of FAT (in bytes) uint32_t fat_size = 1 + ((((bytes * 3) / sector_size) / cluster_size) / 2); uint32_t fat_size_sectors = ((fat_size - 1) / sector_size) + 1; uint32_t root_directory_sector_count = cluster_size - (fat_size_sectors + reserved_sectors); if (!root_directory_sector_count) root_directory_sector_count = cluster_size; uint32_t root_directory_entry_count = (sector_size / sizeof(struct fat_directory_entry)) * root_directory_sector_count; fprintf(stderr, "bytes: %d\n", bytes); fprintf(stderr, "sector_size: %d\n", sector_size); fprintf(stderr, "cluster_size: %d\n", cluster_size); fprintf(stderr, "reserved_sectors: %d\n", reserved_sectors); fprintf(stderr, "fat_size: %d\n", fat_size); fprintf(stderr, "fat_size_sectors: %d\n", fat_size_sectors); fprintf(stderr, "root_directory_sector_count: %d\n", root_directory_sector_count); fprintf(stderr, "root_directory_entry_count: %d\n", root_directory_entry_count); fprintf(stderr, "\n"); memset(mbr, 0, sizeof(mbr)); // jmp instruction mbr[0] = 0xeb; mbr[1] = 0x3c; mbr[2] = 0x90; // OEM name memcpy(mbr+3, "Fomu MBR", 8); // Bytes per sector (512) fat12_write_u16(mbr + 0x0b, sector_size); // Sectors per cluster (8), so cluster is 512 * 8 fat12_write_u8(mbr + 0x0d, cluster_size); // Reserved sector count (8 sectors, to pad things to 4096-byte boundaries) fat12_write_u16(mbr + 0x0e, reserved_sectors); // Number of FATs (1) fat12_write_u8(mbr + 0x10, 1); // Maximum number of root directory entries (16) fat12_write_u16(mbr + 0x11, root_directory_entry_count); // Total number of 512-byte sectors fat12_write_u16(mbr + 0x13, bytes / sector_size); // Type of media (0xf8 == fixed disk) fat12_write_u8(mbr + 0x15, 0xf8); // Sectors per FAT fat12_write_u16(mbr + 0x16, fat_size_sectors); // Sectors per track fat12_write_u16(mbr + 0x18, 32); // Number of heads fat12_write_u16(mbr + 0x1a, 64); // Hidden sectors // mbr[0x1c] = 0x00; // mbr[0x1d] = 0x00; // mbr[0x1e] = 0x00; // mbr[0x1f] = 0x00; // Total number of sectors (unused, since we put it in 0x13) // mbr[0x20] = 0; // mbr[0x21] = 0; // mbr[0x22] = 0; // mbr[0x23] = 0; // BIOS drive fat12_write_u8(mbr + 0x24, 0x80); // Unused fat12_write_u8(mbr + 0x25, 0); // Boot signature fat12_write_u8(mbr + 0x26, 0x29); // Serial number fat12_write_u8(mbr + 0x27, 0xf0); fat12_write_u8(mbr + 0x28, 0xb0); fat12_write_u8(mbr + 0x29, 0x00); fat12_write_u8(mbr + 0x2a, 0x07); // Volume Name memcpy(mbr + 0x2b, "Fomu ", 11); // Filesystem memcpy(mbr + 0x36, "FAT12 ", 8); // Signature fat12_write_u8(mbr + 0xfe, 0x55); fat12_write_u8(mbr + 0xff, 0xaa); // Write MBR to disk if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) { return -1; } offset += sector_size; memset(mbr, 0, sizeof(mbr)); // The first two clusters in the FAT are reserved fat12_set_cluster(mbr, 0, 0xff8); // 0xff8 instead of 0xfff indicates "Hard Disk" fat12_set_cluster(mbr, 1, 0xfff); // 0xfff is reserved value // Root directory is only one cluster // fat12_set_cluster(mbr, 2, 0xfff); if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) { return -1; } offset += sector_size; // Fill in the rest of the FAT uint32_t fat_sector; memset(mbr, 0, sizeof(mbr)); for (fat_sector = 1; fat_sector < fat_size_sectors; fat_sector++) { if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) { return -1; } offset += sector_size; } // Fill in the root directory uint32_t root_directory_sector; for (root_directory_sector = 0; root_directory_sector < cluster_size; root_directory_sector++) { if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) { return -1; } offset += sector_size; } // Fill in the rest of the disk while (offset < bytes) { if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) { return -1; } offset += sector_size; } return 0; }