Nanite/tools/fat/fat.c
2025-05-14 08:53:22 -04:00

184 lines
4.4 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// typedef uint8_t bool;
#define true 1
#define false 0
typedef struct
{
uint8_t BootJumpInstruction[3];
uint8_t OemIdentifier[8];
uint16_t BytesPerSector;
uint8_t SectorsPerCluster;
uint16_t ReservedSectors;
uint8_t FatCount;
uint16_t DirEntryCount;
uint16_t TotalSectors;
uint8_t MediaDescriptorType;
uint16_t SectorsPerFat;
uint16_t SectorsPerTrack;
uint16_t Heads;
uint32_t HiddenSectors;
uint32_t LargeSectorCount;
//Extended Boot Record
uint8_t DriveNumber;
uint8_t _Reserved;
uint8_t Signature;
uint32_t VolumeId; //Serial Can be whatever
uint8_t VolumeLabel[11]; //11 Bytes MUST Be padded with spaces!
uint8_t SystemId[8]; //8 Bytes padded with spaces (use MSWIN4.1 for best compatibility!)
} __attribute__((packed)) BootSector;
typedef struct
{
uint8_t Name[11];
uint8_t Attributes;
uint8_t _Reserved;
uint8_t CreatedTimeTenths;
uint16_t CreatedTime;
uint16_t CreatedDate;
uint16_t AccessedDate;
uint16_t FirstClusterHigh;
uint16_t ModifiedTime;
uint16_t ModifiedDate;
uint16_t FirstClusterLow;
uint32_t Size;
} __attribute__((packed)) DirectoryEntry;
BootSector g_BootSector;
uint8_t* g_Fat = NULL;
DirectoryEntry* g_RootDirectory = NULL;
uint32_t g_RootDirectoryEnd;
bool readBootSector(FILE* disk)
{
return fread(&g_BootSector, sizeof(g_BootSector), 1, disk) > 0;
}
bool readSectors(FILE* disk, uint32_t lba, uint32_t count, void* bufferout)
{
bool ok = true;
ok = ok && (fseek(disk, lba * g_BootSector.BytesPerSector, SEEK_SET) == 0);
ok = ok && (fread(bufferout, g_BootSector.BytesPerSector, count, disk) == count);
return ok;
}
bool readFat(FILE* disk)
{
g_Fat = (uint8_t*) malloc(g_BootSector.SectorsPerFat * g_BootSector.BytesPerSector);
return readSectors(disk, g_BootSector.ReservedSectors, g_BootSector.SectorsPerFat, g_Fat);
}
bool readRootDirectory(FILE* disk)
{
uint32_t lba = g_BootSector.ReservedSectors + g_BootSector.SectorsPerFat * g_BootSector.FatCount;
uint32_t size = sizeof(DirectoryEntry) * g_BootSector.DirEntryCount;
uint32_t sector = (size / g_BootSector.BytesPerSector);
if (size % g_BootSector.BytesPerSector > 0)
sector++;
g_RootDirectoryEnd = lba + sector;
g_RootDirectory = (DirectoryEntry*) malloc(sector * g_BootSector.BytesPerSector);
return readSectors(disk, lba, sector, g_RootDirectory);
}
DirectoryEntry* findFile(const char* name)
{
for (uint32_t i = 0; i < g_BootSector.DirEntryCount; i++)
{
if (memcmp(name, g_RootDirectory[i].Name, 11) == 0)
return &g_RootDirectory[i];
}
return NULL;
}
bool readFile(DirectoryEntry* fileEntry, FILE* disk, uint8_t* outputBuffer)
{
bool ok = true;
uint16_t currentCluster = fileEntry->FirstClusterLow;
do {
uint32_t lba = g_RootDirectoryEnd + (currentCluster - 2) * g_BootSector.SectorsPerCluster;
ok = ok && readSectors(disk, lba, g_BootSector.SectorsPerCluster, outputBuffer);
outputBuffer += g_BootSector.SectorsPerCluster * g_BootSector.BytesPerSector;
uint32_t fatIndex = currentCluster * 3 / 2;
if (currentCluster % 2 == 0)
currentCluster = (*(uint16_t*)(g_Fat + fatIndex)) & 0x0FFF;
else
currentCluster = (*(uint16_t*)(g_Fat + fatIndex)) >> 4;
} while (ok && currentCluster < 0x0FF8);
return ok;
}
int main(int argc, char** argv)
{
if (argc < 3){
printf("Syntax: %s <disk image> <file name>\n", argv[0]);
return -1;
}
FILE* disk = fopen(argv[1], "rb");
if (!disk) {
fprintf(stderr, "Cannot open disk image %s!\n", argv[1]);
return -1;
}
if (!readBootSector(disk)) {
fprintf(stderr, "Could not read boot sector!\n");
return -2;
}
if (!readFat(disk)) {
fprintf(stderr, "Could not read FAT!\n");
free(g_Fat);
return -3;
}
if (!readRootDirectory(disk)) {
fprintf(stderr, "Could not read root!\n");
free(g_Fat);
free(g_RootDirectory);
return -4;
}
DirectoryEntry* fileEntry = findFile(argv[2]);
if (!fileEntry) {
fprintf(stderr, "Could not locate file %s!\n", argv[2]);
free(g_Fat);
free(g_RootDirectory);
return -5;
}
uint8_t* buffer = (uint8_t*) malloc(fileEntry->Size + g_BootSector.BytesPerSector);
if (!readFile(fileEntry, disk, buffer)) {
fprintf(stderr, "Could not read file %s!\n", argv[2]);
free(g_Fat);
free(g_RootDirectory);
free(buffer);
return -5;
}
for (size_t i = 0; i < fileEntry->Size; i++)
{
if (isprint(buffer[i])) fputc(buffer[i], stdout);
//else printf("<%02x>", buffer[i]);
}
printf("\n");
free(g_Fat);
free(g_RootDirectory);
return 0;
}