finish fat.c
This commit is contained in:
3 files changed
+188
-1
No files matched your search
@@ -1,9 +1,13 @@
|
|||||||
ASM=nasm
|
ASM=nasm
|
||||||
|
CC=gcc
|
||||||
|
|
||||||
SRC_DIR=src
|
SRC_DIR=src
|
||||||
|
TOOLS_DIR=tools
|
||||||
BUILD_DIR=build
|
BUILD_DIR=build
|
||||||
|
|
||||||
.PHONY: all floppy_image kernel bootloader clean always
|
.PHONY: all floppy_image kernel bootloader clean always tools_fat
|
||||||
|
|
||||||
|
all: floppy_image tools_fat
|
||||||
|
|
||||||
#
|
#
|
||||||
# Floppy image
|
# Floppy image
|
||||||
@@ -15,6 +19,8 @@ $(BUILD_DIR)/main_floppy.img: bootloader kernel
|
|||||||
mkfs.fat -F 12 -n "NBOS" $(BUILD_DIR)/main_floppy.img
|
mkfs.fat -F 12 -n "NBOS" $(BUILD_DIR)/main_floppy.img
|
||||||
dd if=$(BUILD_DIR)/bootloader.bin of=$(BUILD_DIR)/main_floppy.img conv=notrunc
|
dd if=$(BUILD_DIR)/bootloader.bin of=$(BUILD_DIR)/main_floppy.img conv=notrunc
|
||||||
mcopy -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/kernel.bin "::kernel.bin"
|
mcopy -i $(BUILD_DIR)/main_floppy.img $(BUILD_DIR)/kernel.bin "::kernel.bin"
|
||||||
|
mcopy -i $(BUILD_DIR)/main_floppy.img test.txt "::test.txt"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bootlader
|
# Bootlader
|
||||||
@@ -32,6 +38,15 @@ kernel: $(BUILD_DIR)/kernel.bin
|
|||||||
$(BUILD_DIR)/kernel.bin: always
|
$(BUILD_DIR)/kernel.bin: always
|
||||||
$(ASM) $(SRC_DIR)/kernel/main.asm -f bin -o $(BUILD_DIR)/kernel.bin
|
$(ASM) $(SRC_DIR)/kernel/main.asm -f bin -o $(BUILD_DIR)/kernel.bin
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tools
|
||||||
|
#
|
||||||
|
tools_fat: $(BUILD_DIR)/tools/fat
|
||||||
|
|
||||||
|
$(BUILD_DIR)/tools/fat: always $(TOOLS_DIR)/fat/fat.c
|
||||||
|
mkdir -p $(BUILD_DIR)/tools
|
||||||
|
$(CC) -g -o $(BUILD_DIR)/tools/fat $(TOOLS_DIR)/fat/fat.c
|
||||||
|
|
||||||
#
|
#
|
||||||
# Always
|
# Always
|
||||||
#
|
#
|
||||||
|
|||||||
+171
@@ -0,0 +1,171 @@
|
|||||||
|
#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 SectorPerCluster;
|
||||||
|
uint16_t ReservedSectors;
|
||||||
|
uint8_t FatCount;
|
||||||
|
uint16_t DirEntryCount;
|
||||||
|
uint16_t TotalSectors;
|
||||||
|
uint8_t MediaDescriptionType;
|
||||||
|
uint16_t SectorsPerFat;
|
||||||
|
uint16_t SectorsPerTrack;
|
||||||
|
uint16_t Heads;
|
||||||
|
uint32_t HiddenSectors;
|
||||||
|
uint32_t LargeSectorCount;
|
||||||
|
|
||||||
|
// extended boot record
|
||||||
|
uint8_t DriveNuber;
|
||||||
|
uint8_t _Reserved;
|
||||||
|
uint8_t Signature;
|
||||||
|
uint32_t VolumeId; // serial number, value doesn't matter
|
||||||
|
uint8_t VolumbeLabel[11]; // 11 bytes, padded with spaces
|
||||||
|
uint8_t SystemId[9]
|
||||||
|
|
||||||
|
// ... we don't care about code ...
|
||||||
|
} __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 sectors = (size / g_BootSector.BytesPerSector);
|
||||||
|
if (size % g_BootSector.BytesPerSector > 0)
|
||||||
|
sectors++;
|
||||||
|
|
||||||
|
g_RootDirectoryEnd = lba + sectors;
|
||||||
|
g_RootDirectory = (DirectoryEntry*) malloc(sectors * g_BootSector.BytesPerSector);
|
||||||
|
return readSectors(disk, lba, sectors, 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.SectorPerCluster;
|
||||||
|
ok = ok && readSectors(disk, lba, g_BootSector.SectorPerCluster, outputBuffer);
|
||||||
|
outputBuffer += g_BootSector.SectorPerCluster * 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!", 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 boot FAT!\n");
|
||||||
|
free(g_Fat);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readRootDirectory(disk)) {
|
||||||
|
fprintf(stderr, "Could not read boot FAT!\n");
|
||||||
|
free(g_Fat);
|
||||||
|
free(g_RootDirectory);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryEntry* fileEntry = findFile(argv[2]);
|
||||||
|
if (!fileEntry) {
|
||||||
|
fprintf(stderr, "Could not find 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;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user