Created
March 7, 2017 12:46
-
-
Save jeremysinger/161a77f2e5932fb706f5c8b664cf60a0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define BOOT_SECTOR_OFFSET 0 | |
typedef struct { | |
unsigned char jmp[3]; | |
char oem[8]; | |
unsigned short sector_size; | |
unsigned char sectors_per_cluster; | |
unsigned short reserved_sectors; | |
unsigned char number_of_fats; | |
unsigned short root_dir_entries; | |
unsigned short total_sectors_short; // if zero, later field is used | |
unsigned char media_descriptor; | |
unsigned short fat_size_sectors; | |
unsigned short sectors_per_track; | |
unsigned short number_of_heads; | |
unsigned int hidden_sectors; | |
unsigned int total_sectors_long; | |
unsigned char drive_number; | |
unsigned char current_head; | |
unsigned char boot_signature; | |
unsigned int volume_id; | |
char volume_label[11]; | |
char fs_type[8]; | |
char boot_code[448]; | |
unsigned short boot_sector_signature; | |
} __attribute((packed)) Fat16BootSector; | |
typedef struct { | |
unsigned char filename[8]; | |
unsigned char ext[3]; | |
unsigned char attributes; | |
unsigned char reserved[10]; | |
unsigned short modify_time; | |
unsigned short modify_date; | |
unsigned short starting_cluster; | |
unsigned int file_size; | |
} __attribute((packed)) Fat16Entry; | |
// Below is a file that fits in a single cluster | |
/* char *name = "limerick"; */ | |
/* char *ext = "txt"; */ | |
/* char *short_poem = "The Owl and the Pussy-cat went to sea \ */ | |
/* In a beautiful pea green boat, \ */ | |
/* They took some honey, and plenty of money, \ */ | |
/* Wrapped up in a five pound note."; */ | |
// Below is a file that spans two clusters | |
char *name = "sonnet18"; | |
char *ext = "txt"; | |
char *poem = | |
"Shall I compare thee to a summer's day? \ | |
Thou art more lovely and more temperate: \ | |
Rough winds do shake the darling buds of May, \ | |
And summer's lease hath all too short a date: \ | |
Sometime too hot the eye of heaven shines, \ | |
And often is his gold complexion dimm'd; \ | |
And every fair from fair sometime declines, \ | |
By chance, or nature's changing course, untrimm'd: \ | |
But thy eternal summer shall not fade, \ | |
Nor lose possession of that fair thou ow'st; \ | |
Nor shall Death brag thou wander'st in his shade, \ | |
When in eternal lines to time thou grow'st: \ | |
So long as men can breathe, or eyes can see, \ | |
So long lives this, and this gives life to thee."; | |
void print_file_info(Fat16Entry *entry) { | |
switch(entry->filename[0]) { | |
case 0x00: | |
return; // unused entry | |
case 0xE5: | |
printf("Deleted file: [?%.7s.%.3s]\n", entry->filename+1, entry->ext); | |
return; | |
case 0x05: | |
printf("File starting with 0xE5: [%c%.7s.%.3s]\n", 0xE5, entry->filename+1, entry->ext); | |
break; | |
case 0x2E: | |
printf("Directory: [%.8s.%.3s]\n", entry->filename, entry->ext); | |
break; | |
default: | |
printf("File: [%.8s.%.3s]\n", entry->filename, entry->ext); | |
} | |
printf(" Modified: %04d-%02d-%02d %02d:%02d.%02d Start: [%04X] Size: %d\n", | |
1980 + (entry->modify_date >> 9), (entry->modify_date >> 5) & 0xF, entry->modify_date & 0x1F, | |
(entry->modify_time >> 11), (entry->modify_time >> 5) & 0x3F, entry->modify_time & 0x1F, | |
entry->starting_cluster, entry->file_size); | |
} | |
int main() { | |
FILE * in = fopen("example.img", "r+b"); // r+ means read and write | |
int i, n; | |
char fat_ptr[2]; | |
Fat16BootSector bs; | |
Fat16Entry *entry; | |
printf("boot sector struct size %lu\n", sizeof(Fat16BootSector)); | |
fseek(in, BOOT_SECTOR_OFFSET, SEEK_SET); | |
fread(&bs, sizeof(Fat16BootSector), 1, in); | |
printf("Now at 0x%lX, sector size %d, FAT size %d sectors, %d FATs\n\n", | |
ftell(in), bs.sector_size, bs.fat_size_sectors, bs.number_of_fats); | |
// Now let's add a multicluster file ... | |
// add a new entry as 1st file in root directory | |
// (1) first create FAT root dir entry | |
printf("creating root dir entry\n"); | |
entry = (Fat16Entry*)calloc(1, sizeof(Fat16Entry)); | |
memcpy(entry->filename, name, 8); | |
memcpy(entry->ext, ext, 3); | |
entry->attributes = '\0'; | |
entry->starting_cluster = (unsigned short)2; | |
entry->file_size = strlen(poem); | |
// move to place in root dir and write entry | |
fseek(in, (bs.reserved_sectors + bs.fat_size_sectors * bs.number_of_fats) * | |
bs.sector_size, SEEK_SET); | |
fwrite(entry, sizeof(Fat16Entry), 1, in); | |
printf("written root dir entry\n"); | |
// (2) then allocate file into consecutive empty clusters in the | |
// data region, starting at cluster 2 | |
// write poem string here... | |
printf("writing to data cluster\n"); | |
fseek(in, (1/*rootdir*/ + bs.reserved_sectors + bs.fat_size_sectors * bs.number_of_fats) *bs.sector_size, SEEK_SET); | |
fwrite(poem, sizeof(char), strlen(poem), in); | |
printf("written data\n"); | |
// (3) then update FAT entries for this file | |
// Entry is for cluster 2, and consecutive clusters | |
fseek(in, sizeof(bs) + 2*2*sizeof(char), SEEK_SET); // seek past end of boot sector, into FAT | |
for (n = 2; n < 2 + (strlen(poem)/(bs.sector_size*bs.sectors_per_cluster)); n++) { | |
printf("updating FAT cluster entry %d\n", n); | |
fat_ptr[0] = (char)(n+1); // assume n<256 | |
fat_ptr[1] = (char)0; | |
fwrite(fat_ptr, sizeof(char), 2, in); | |
printf("updated FAT cluster entry %d with value %d\n", n, n+1); | |
//fseek(in, n*2*sizeof(char), SEEK_CUR); // seek to correct FAT entry | |
// no need for subsequent fseek since fwrite bumps file pointer? | |
} | |
// now write -1 in final cluster entry in FAT | |
printf("updating FAT cluster entry %d\n", n); | |
fat_ptr[0] = (char)0xff; | |
fat_ptr[1] = (char)0xff; | |
fwrite(fat_ptr, sizeof(char), 2, in); | |
printf("updated FAT cluster entry %d with value 0xffff\n", n); | |
fclose(in); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# gen_fat_fs.py | |
# Jeremy Singer | |
# 26 Feb 2017 | |
## simple python script to create an example FAT | |
## filesystem image, from scratch | |
image = 'example.img' | |
# create (or overwrite) the file and start writing bytes into it | |
f = open(image, 'wb') | |
# first three bytes of boot sector are 'magic value' | |
f.write( bytearray([0xeb, 0x3c, 0x90]) ) | |
# next 8 bytes are manufacturer name, in ASCII | |
f.write( 'GLASGOW '.encode('ascii') ) | |
# next 2 bytes are bytes per block - 512 is standard | |
# this is in little endian format - so 0x200 is 0x00, 0x02 | |
# A block == A sector in FAT terminology | |
f.write( bytearray([0x00, 0x02]) ) | |
# next byte, number of blocks per allocation unit - we say 1 for simplicity | |
# An allocation unit == A cluster in FAT terminology | |
f.write( bytearray([0x01]) ) | |
# next two bytes, number of reserved blocks - we | |
# say 1 for boot sector only | |
f.write( bytearray([0x01, 0x00]) ) | |
# next byte, number of File Allocation tables - can have multiple | |
# tables for redundancy - we'll stick with 1 for now | |
f.write( bytearray([0x01]) ) | |
# next two bytes, number of root directory entries - including blanks | |
# let's say 16 files in root for now - which means the root directory | |
# will occupy a single sector | |
f.write( bytearray([0x10, 0x00]) ) | |
# next two bytes, number of blocks in the entire disk - we want a 4 meg disk, | |
# so need 8192 0.5K blocks == 2^13 == 0x00 0x20 | |
f.write( bytearray([0x00, 0x20]) ) | |
# single byte media descriptor - magic value 0xf8?? | |
f.write( bytearray([0xf8]) ) | |
# next two bytes, number of blocks for FAT | |
# FAT needs two bytes per block, we have 8192 blocks on disk | |
# 512 bytes per block - i.e. can store FAT metadata for 256 blocks in | |
# a single block, so need 8192/256 blocks == 2^13/2^8 == 2^5 == 32 | |
f.write( bytearray([0x20, 0x00]) ) | |
# next 8 bytes are legacy values, can all be 0 | |
f.write( bytearray([0,0,0,0,0,0,0,0]) ) | |
# next 4 bytes are total number of blocks in entire disk - if it overflows | |
# previous 2 byte entry ... otherwise leave at 0 | |
f.write( bytearray([0x00, 0x00, 0x00, 0x00]) ) | |
# next 2 bytes are legacy values, can all be 0 | |
f.write( bytearray([0x80,0]) ) | |
# magic value 29 - for FAT16 extended signature | |
f.write( bytearray([0x29]) ) | |
# next 4 bytes are volume serial number (unique id) | |
f.write( bytearray([0x41,0x42,0x43,0x44]) ) | |
# next 11 bytes are volume label (name) - pad with trailing spaces | |
f.write( "TEST_DISK ".encode('ascii')) | |
# next 8 bytes are file system identifier - pad with trailing spaces | |
f.write( "FAT16 ".encode('ascii')) | |
for i in range(0,0x1c0): | |
f.write( bytearray([0]) ) | |
# end of boot sector magic marker | |
f.write( bytearray([0x55, 0xaa]) ) | |
########### | |
# next lot of sectors is file allocation table | |
# each entry has 2 bytes, we need 8192 entries (== 32 blocks) | |
# first two entries are magic value (media descriptor) then three 0xff values | |
f.write( bytearray([0xf8, 0xff]) ) | |
f.write( bytearray([0xff, 0xff]) ) | |
# subsequent entries are 0 | |
for i in range(2, 8192): | |
f.write( bytearray([0x00, 0x00]) ) | |
############ | |
# next sector is root directory | |
########### | |
# each file entry occupies 32 bytes - we just no entries for now - all zeros. | |
for i in range(0, 16): | |
for j in range(0,32): | |
f.write( bytearray([0]) ) | |
##### 8192 blank sectors (after root) | |
for i in range(0,8192): | |
f.write( bytearray([0x00] * 512)) | |
f.close() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define BOOT_SECTOR_OFFSET 0 | |
typedef struct { | |
unsigned char jmp[3]; | |
char oem[8]; | |
unsigned short sector_size; | |
unsigned char sectors_per_cluster; | |
unsigned short reserved_sectors; | |
unsigned char number_of_fats; | |
unsigned short root_dir_entries; | |
unsigned short total_sectors_short; // if zero, later field is used | |
unsigned char media_descriptor; | |
unsigned short fat_size_sectors; | |
unsigned short sectors_per_track; | |
unsigned short number_of_heads; | |
unsigned int hidden_sectors; | |
unsigned int total_sectors_long; | |
unsigned char drive_number; | |
unsigned char current_head; | |
unsigned char boot_signature; | |
unsigned int volume_id; | |
char volume_label[11]; | |
char fs_type[8]; | |
char boot_code[448]; | |
unsigned short boot_sector_signature; | |
} __attribute((packed)) Fat16BootSector; | |
typedef struct { | |
unsigned char filename[8]; | |
unsigned char ext[3]; | |
unsigned char attributes; | |
unsigned char reserved[10]; | |
unsigned short modify_time; | |
unsigned short modify_date; | |
unsigned short starting_cluster; | |
unsigned int file_size; | |
} __attribute((packed)) Fat16Entry; | |
// Below is a file that fits in a single cluster | |
/* char *name = "limerick"; */ | |
/* char *ext = "txt"; */ | |
/* char *short_poem = "The Owl and the Pussy-cat went to sea \ */ | |
/* In a beautiful pea green boat, \ */ | |
/* They took some honey, and plenty of money, \ */ | |
/* Wrapped up in a five pound note."; */ | |
// Below is a file that spans two clusters | |
char *name = "sonnet18"; | |
char *ext = "txt"; | |
char *poem = | |
"Shall I compare thee to a summer's day? \ | |
Thou art more lovely and more temperate: \ | |
Rough winds do shake the darling buds of May, \ | |
And summer's lease hath all too short a date: \ | |
Sometime too hot the eye of heaven shines, \ | |
And often is his gold complexion dimm'd; \ | |
And every fair from fair sometime declines, \ | |
By chance, or nature's changing course, untrimm'd: \ | |
But thy eternal summer shall not fade, \ | |
Nor lose possession of that fair thou ow'st; \ | |
Nor shall Death brag thou wander'st in his shade, \ | |
When in eternal lines to time thou grow'st: \ | |
So long as men can breathe, or eyes can see, \ | |
So long lives this, and this gives life to thee."; | |
void print_file_info(Fat16Entry *entry) { | |
switch(entry->filename[0]) { | |
case 0x00: | |
return; // unused entry | |
case 0xE5: | |
printf("Deleted file: [?%.7s.%.3s]\n", entry->filename+1, entry->ext); | |
return; | |
case 0x05: | |
printf("File starting with 0xE5: [%c%.7s.%.3s]\n", 0xE5, entry->filename+1, entry->ext); | |
break; | |
case 0x2E: | |
printf("Directory: [%.8s.%.3s]\n", entry->filename, entry->ext); | |
break; | |
default: | |
printf("File: [%.8s.%.3s]\n", entry->filename, entry->ext); | |
} | |
printf(" Modified: %04d-%02d-%02d %02d:%02d.%02d Start: [%04X] Size: %d\n", | |
1980 + (entry->modify_date >> 9), (entry->modify_date >> 5) & 0xF, entry->modify_date & 0x1F, | |
(entry->modify_time >> 11), (entry->modify_time >> 5) & 0x3F, entry->modify_time & 0x1F, | |
entry->starting_cluster, entry->file_size); | |
} | |
int main() { | |
FILE * in = fopen("example.img", "r+b"); // r+ means read and write | |
int i, n; | |
char fat_ptr[2]; | |
Fat16BootSector bs; | |
Fat16Entry *entry; | |
printf("boot sector struct size %lu\n", sizeof(Fat16BootSector)); | |
fseek(in, BOOT_SECTOR_OFFSET, SEEK_SET); | |
fread(&bs, sizeof(Fat16BootSector), 1, in); | |
printf("Now at 0x%lX, sector size %d, FAT size %d sectors, %d FATs\n\n", | |
ftell(in), bs.sector_size, bs.fat_size_sectors, bs.number_of_fats); | |
// Now let's add a multicluster file ... | |
// add a new entry as 1st file in root directory | |
// (1) first create FAT root dir entry | |
printf("creating root dir entry\n"); | |
entry = (Fat16Entry*)calloc(1, sizeof(Fat16Entry)); | |
memcpy(entry->filename, name, 8); | |
memcpy(entry->ext, ext, 3); | |
entry->attributes = '\0'; | |
entry->starting_cluster = (unsigned short)2; | |
entry->file_size = strlen(poem); | |
// move to place in root dir and write entry | |
fseek(in, (bs.reserved_sectors + bs.fat_size_sectors * bs.number_of_fats) * | |
bs.sector_size, SEEK_SET); | |
fwrite(entry, sizeof(Fat16Entry), 1, in); | |
printf("written root dir entry\n"); | |
// (2) then allocate file into consecutive empty clusters in the | |
// data region, starting at cluster 2 | |
// write poem string here... | |
printf("writing to data cluster\n"); | |
fseek(in, (1/*rootdir*/ + bs.reserved_sectors + bs.fat_size_sectors * bs.number_of_fats) *bs.sector_size, SEEK_SET); | |
fwrite(poem, sizeof(char), strlen(poem), in); | |
printf("written data\n"); | |
// (3) then update FAT entries for this file | |
// Entry is for cluster 2, and consecutive clusters | |
fseek(in, sizeof(bs) + 2*2*sizeof(char), SEEK_SET); // seek past end of boot sector, into FAT | |
for (n = 2; n < 2 + (strlen(poem)/(bs.sector_size*bs.sectors_per_cluster)); n++) { | |
printf("updating FAT cluster entry %d\n", n); | |
fat_ptr[0] = (char)(n+1); // assume n<256 | |
fat_ptr[1] = (char)0; | |
fwrite(fat_ptr, sizeof(char), 2, in); | |
printf("updated FAT cluster entry %d with value %d\n", n, n+1); | |
//fseek(in, n*2*sizeof(char), SEEK_CUR); // seek to correct FAT entry | |
// no need for subsequent fseek since fwrite bumps file pointer? | |
} | |
// now write -1 in final cluster entry in FAT | |
printf("updating FAT cluster entry %d\n", n); | |
fat_ptr[0] = (char)0xff; | |
fat_ptr[1] = (char)0xff; | |
fwrite(fat_ptr, sizeof(char), 2, in); | |
printf("updated FAT cluster entry %d with value 0xffff\n", n); | |
fclose(in); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment