mkfs: first working version
It can create a basic filesystem of arbitrary size. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
ab97abe22a
commit
f68f8215b7
7
Makefile
7
Makefile
@ -1,9 +1,12 @@
|
|||||||
CFLAGS ?= -Iinclude
|
CFLAGS ?= -Iinclude
|
||||||
|
|
||||||
all: build build/test-get-set-cluster
|
all: build build/test-get-set-cluster build/test-mkfs-simple
|
||||||
|
|
||||||
build:
|
build:
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|
||||||
build/test-get-set-cluster:
|
build/test-get-set-cluster: tests/get-set-cluster.c src/fat12.c include/fat12.h
|
||||||
$(CC) $(CFLAGS) tests/get-set-cluster.c src/fat12.c -o build/test-get-set-cluster
|
$(CC) $(CFLAGS) tests/get-set-cluster.c src/fat12.c -o build/test-get-set-cluster
|
||||||
|
|
||||||
|
build/test-mkfs-simple: tests/mkfs-simple.c src/fat12.c include/fat12.h src/mkfat.c src/io.c
|
||||||
|
$(CC) $(CFLAGS) tests/mkfs-simple.c src/mkfat.c src/fat12.c src/io.c -o $@
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void fat12_write_u8(void *ptr, uint8_t val);
|
||||||
|
uint8_t fat12_read_u8(void *ptr);
|
||||||
void fat12_write_u16(void *ptr, uint16_t val);
|
void fat12_write_u16(void *ptr, uint16_t val);
|
||||||
uint16_t fat12_read_u16(void *ptr);
|
uint16_t fat12_read_u16(void *ptr);
|
||||||
void fat12_set_cluster(void *fat, uint32_t cluster, uint32_t value);
|
void fat12_set_cluster(void *fat, uint32_t cluster, uint32_t value);
|
||||||
@ -11,4 +13,20 @@ uint32_t fat12_get_cluster(void *fat, uint32_t cluster);
|
|||||||
int fat12_defrag(int fd);
|
int fat12_defrag(int fd);
|
||||||
int fat12_mkfs(int fd, uint32_t bytes);
|
int fat12_mkfs(int fd, uint32_t bytes);
|
||||||
|
|
||||||
|
struct fat_directory_entry {
|
||||||
|
uint8_t file_name[8];
|
||||||
|
uint8_t extension[3];
|
||||||
|
uint8_t file_attributes;
|
||||||
|
uint8_t reserved1;
|
||||||
|
uint8_t ctime_ms;
|
||||||
|
uint8_t ctime_hms[2];
|
||||||
|
uint8_t ctime_date[2];
|
||||||
|
uint8_t atime_date[2];
|
||||||
|
uint8_t ea_index[2];
|
||||||
|
uint8_t mtime_hms[2];
|
||||||
|
uint8_t mtime_date[2];
|
||||||
|
uint8_t first_cluster[2];
|
||||||
|
uint8_t file_size[4];
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* PANG_O_LIN_FAT12_H__ */
|
#endif /* PANG_O_LIN_FAT12_H__ */
|
11
src/fat12.c
11
src/fat12.c
@ -1,5 +1,16 @@
|
|||||||
#include "fat12.h"
|
#include "fat12.h"
|
||||||
|
|
||||||
|
|
||||||
|
void fat12_write_u8(void *ptr, uint8_t val) {
|
||||||
|
((uint8_t *)ptr)[0] = (val >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t fat12_read_u8(void *ptr) {
|
||||||
|
uint16_t val = 0;
|
||||||
|
val |= (((uint8_t *)ptr)[0] << 0) & 0xff;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
void fat12_write_u16(void *ptr, uint16_t val) {
|
void fat12_write_u16(void *ptr, uint16_t val) {
|
||||||
((uint8_t *)ptr)[0] = (val >> 0) & 0xff;
|
((uint8_t *)ptr)[0] = (val >> 0) & 0xff;
|
||||||
((uint8_t *)ptr)[1] = (val >> 8) & 0xff;
|
((uint8_t *)ptr)[1] = (val >> 8) & 0xff;
|
||||||
|
112
src/mkfat.c
112
src/mkfat.c
@ -2,31 +2,40 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fat12.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
struct directory_entry {
|
// Create a FAT12 filesystem using the given file descriptor,
|
||||||
uint8_t file_name[8];
|
// with length _bytes_.
|
||||||
uint8_t extension[3];
|
// It will define a root directory size and padding size so that the file sectors
|
||||||
uint8_t file_attributes;
|
// end up on 4096-byte boundaries.
|
||||||
uint8_t reserved1;
|
|
||||||
uint8_t ctime_ms;
|
|
||||||
uint8_t ctime_hms[2];
|
|
||||||
uint8_t ctime_date[2];
|
|
||||||
uint8_t atime_date[2];
|
|
||||||
uint8_t ea_index[2];
|
|
||||||
uint8_t mtime_hms[2];
|
|
||||||
uint8_t mtime_date[2];
|
|
||||||
uint8_t first_cluster[2];
|
|
||||||
uint8_t file_size[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
int fat12_mkfs(int fd, uint32_t bytes) {
|
int fat12_mkfs(int fd, uint32_t bytes) {
|
||||||
uint8_t mbr[512];
|
uint8_t mbr[512];
|
||||||
const uint16_t sector_size = 512;
|
const uint32_t sector_size = 512;
|
||||||
const uint8_t cluster_size = 8; // 4 kiB cluster sizes match flash erase block size
|
uint32_t cluster_size = 4096 / sector_size; // 4 kiB cluster sizes match flash erase block size
|
||||||
|
if (bytes > 16000) {
|
||||||
|
// 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?
|
// 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 = 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);
|
||||||
|
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));
|
memset(mbr, 0, sizeof(mbr));
|
||||||
|
|
||||||
@ -42,25 +51,25 @@ int fat12_mkfs(int fd, uint32_t bytes) {
|
|||||||
fat12_write_u16(mbr + 0x0b, sector_size);
|
fat12_write_u16(mbr + 0x0b, sector_size);
|
||||||
|
|
||||||
// Sectors per cluster (8), so cluster is 512 * 8
|
// Sectors per cluster (8), so cluster is 512 * 8
|
||||||
mbr[0x0d] = cluster_size;
|
fat12_write_u8(mbr + 0x0d, cluster_size);
|
||||||
|
|
||||||
// Reserved sector count (8 sectors, to pad things to 4096-byte boundaries)
|
// Reserved sector count (8 sectors, to pad things to 4096-byte boundaries)
|
||||||
fat12_write_u16(mbr + 0x0e, cluster_size);
|
fat12_write_u16(mbr + 0x0e, reserved_sectors);
|
||||||
|
|
||||||
// Number of FATs (1)
|
// Number of FATs (1)
|
||||||
mbr[0x10] = 1;
|
fat12_write_u8(mbr + 0x10, 1);
|
||||||
|
|
||||||
// Maximum number of root directory entries (16)
|
// Maximum number of root directory entries (16)
|
||||||
fat12_write_u16(mbr + 0x11, 32);
|
fat12_write_u16(mbr + 0x11, root_directory_entry_count);
|
||||||
|
|
||||||
// Total number of 512-byte sectors
|
// Total number of 512-byte sectors
|
||||||
fat12_write_u16(mbr + 0x13, bytes / sector_size);
|
fat12_write_u16(mbr + 0x13, bytes / sector_size);
|
||||||
|
|
||||||
// Type of media (0xf8 == fixed disk)
|
// Type of media (0xf8 == fixed disk)
|
||||||
mbr[0x15] = 0xf8;
|
fat12_write_u8(mbr + 0x15, 0xf8);
|
||||||
|
|
||||||
// Sectors per FAT
|
// Sectors per FAT
|
||||||
fat12_write_u16(mbr + 0x16, fat_size);
|
fat12_write_u16(mbr + 0x16, fat_size_sectors);
|
||||||
|
|
||||||
// Sectors per track
|
// Sectors per track
|
||||||
fat12_write_u16(mbr + 0x18, 32);
|
fat12_write_u16(mbr + 0x18, 32);
|
||||||
@ -69,31 +78,31 @@ int fat12_mkfs(int fd, uint32_t bytes) {
|
|||||||
fat12_write_u16(mbr + 0x1a, 64);
|
fat12_write_u16(mbr + 0x1a, 64);
|
||||||
|
|
||||||
// Hidden sectors
|
// Hidden sectors
|
||||||
mbr[0x1c] = 0x00;
|
// mbr[0x1c] = 0x00;
|
||||||
mbr[0x1d] = 0x00;
|
// mbr[0x1d] = 0x00;
|
||||||
mbr[0x1e] = 0x00;
|
// mbr[0x1e] = 0x00;
|
||||||
mbr[0x1f] = 0x00;
|
// mbr[0x1f] = 0x00;
|
||||||
|
|
||||||
// Total number of sectors (unused, since we put it in 0x13)
|
// Total number of sectors (unused, since we put it in 0x13)
|
||||||
mbr[0x20] = 0;
|
// mbr[0x20] = 0;
|
||||||
mbr[0x21] = 0;
|
// mbr[0x21] = 0;
|
||||||
mbr[0x22] = 0;
|
// mbr[0x22] = 0;
|
||||||
mbr[0x23] = 0;
|
// mbr[0x23] = 0;
|
||||||
|
|
||||||
// BIOS drive
|
// BIOS drive
|
||||||
mbr[0x24] = 0x80;
|
fat12_write_u8(mbr + 0x24, 0x80);
|
||||||
|
|
||||||
// Unused
|
// Unused
|
||||||
mbr[0x25] = 0;
|
fat12_write_u8(mbr + 0x25, 0);
|
||||||
|
|
||||||
// Boot signature
|
// Boot signature
|
||||||
mbr[0x26] = 0x29;
|
fat12_write_u8(mbr + 0x26, 0x29);
|
||||||
|
|
||||||
// Serial number
|
// Serial number
|
||||||
mbr[0x27] = 0xf0;
|
fat12_write_u8(mbr + 0x27, 0xf0);
|
||||||
mbr[0x28] = 0xb0;
|
fat12_write_u8(mbr + 0x28, 0xb0);
|
||||||
mbr[0x29] = 0x00;
|
fat12_write_u8(mbr + 0x29, 0x00);
|
||||||
mbr[0x2a] = 0x07;
|
fat12_write_u8(mbr + 0x2a, 0x07);
|
||||||
|
|
||||||
// Volume Name
|
// Volume Name
|
||||||
memcpy(mbr + 0x2b, "Fomu ", 11);
|
memcpy(mbr + 0x2b, "Fomu ", 11);
|
||||||
@ -102,8 +111,8 @@ int fat12_mkfs(int fd, uint32_t bytes) {
|
|||||||
memcpy(mbr + 0x36, "FAT12 ", 8);
|
memcpy(mbr + 0x36, "FAT12 ", 8);
|
||||||
|
|
||||||
// Signature
|
// Signature
|
||||||
mbr[0xfe] = 0x55;
|
fat12_write_u8(mbr + 0xfe, 0x55);
|
||||||
mbr[0xff] = 0xaa;
|
fat12_write_u8(mbr + 0xff, 0xaa);
|
||||||
|
|
||||||
// Write MBR to disk
|
// Write MBR to disk
|
||||||
if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||||||
@ -112,16 +121,33 @@ int fat12_mkfs(int fd, uint32_t bytes) {
|
|||||||
|
|
||||||
memset(mbr, 0, sizeof(mbr));
|
memset(mbr, 0, sizeof(mbr));
|
||||||
|
|
||||||
// The first two clusters in the FAT are reserved, and must be 0xff
|
// 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, 0, 0xff8); // 0xff8 instead of 0xfff indicates "Hard Disk"
|
||||||
fat12_set_cluster(mbr, 1, 0xfff); // 0xfff is reserved value
|
fat12_set_cluster(mbr, 1, 0xfff); // 0xfff is reserved value
|
||||||
|
|
||||||
// Root directory is only one cluster
|
// Root directory is only one cluster
|
||||||
fat12_set_cluster(mbr, 2, 0xfff);
|
// fat12_set_cluster(mbr, 2, 0xfff);
|
||||||
|
|
||||||
if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
37
tests/mkfs-simple.c
Normal file
37
tests/mkfs-simple.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fat12.h"
|
||||||
|
|
||||||
|
static int make_image(const char *name, uint32_t size) {
|
||||||
|
|
||||||
|
int fd = open(name, O_WRONLY | O_CREAT, 0777);
|
||||||
|
if (-1 == fd) {
|
||||||
|
fprintf(stderr, "couldn't open %s: %s\n", name, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == fat12_mkfs(fd, size)) {
|
||||||
|
fprintf(stderr, "couldn't make fat12 on %s: %s\n", name, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret += make_image("fat12-1300k.img", 1300 * 1024);
|
||||||
|
// ret += make_image("fat12-1800k.img", 1800 * 1024);
|
||||||
|
// ret += make_image("fat12-128k.img", 128 * 1024);
|
||||||
|
ret += make_image("fat12-16M.img", 16 * 1024 * 1024);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user