commit some source
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
2afca97177
commit
5fb4ea8474
14
include/fat12.h
Normal file
14
include/fat12.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef PANG_O_LIN_FAT12_H__
|
||||||
|
#define PANG_O_LIN_FAT12_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void fat12_write_u16(void *ptr, uint16_t val);
|
||||||
|
uint16_t fat12_read_u16(void *ptr);
|
||||||
|
void fat12_set_cluster(void *fat, uint32_t cluster, uint32_t value);
|
||||||
|
uint32_t fat12_get_cluster(void *fat, uint32_t cluster);
|
||||||
|
|
||||||
|
int fat12_defrag(int fd);
|
||||||
|
int fat12_mkfs(int fd, uint32_t bytes);
|
||||||
|
|
||||||
|
#endif /* PANG_O_LIN_FAT12_H__ */
|
14
include/io.h
Normal file
14
include/io.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef PANG_O_LIN_IO_H__
|
||||||
|
#define PANG_O_LIN_IO_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef unix
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssize_t pang_write(int fd, const void *buf, size_t count);
|
||||||
|
ssize_t pang_read(int fd, void *buf, size_t count);
|
||||||
|
off_t pang_seek(int fd, off_t offset, int whence);
|
||||||
|
|
||||||
|
#endif /* PANG_O_LIN_IO_H__ */
|
45
src/defrag.c
Normal file
45
src/defrag.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
#define try(x) do { int i = (x); if (i == -1) { return -1 } } while (0)
|
||||||
|
|
||||||
|
int fat12_defrag(int fd) {
|
||||||
|
uint8_t buf[512];
|
||||||
|
|
||||||
|
// Read in MBR and figure out where the FAT begins and ends
|
||||||
|
try(pang_seek(fd, 0, SEEK_SET));
|
||||||
|
|
||||||
|
// Actually read in the MBR
|
||||||
|
try(pang_read(fd, buf, sizeof(buf)));
|
||||||
|
|
||||||
|
// We only operate on 512-byte sector sizes
|
||||||
|
if (fat12_read_u16(buf + 0x0b) != 512) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We require the cluster size to be 4096 (8 * 512)
|
||||||
|
if (buf[0x0d] != 8) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To ensure the erase block is correct, require 4096-bytes
|
||||||
|
// of reserved data
|
||||||
|
if (fat12_read_u16(buf + 0x0e) != 4096) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also, we only support 1 FAT
|
||||||
|
if (buf[0x10] != 1) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 32 root entries keeps it padded correctly.
|
||||||
|
if (fat12_read_u16(mbr + 0x11, 32) != 32) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total number of 512-byte sectors
|
||||||
|
fat12_write_u16(mbr + 0x13, bytes / sector_size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
41
src/fat12.c
Normal file
41
src/fat12.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "fat12.h"
|
||||||
|
|
||||||
|
void fat12_write_u16(void *ptr, uint16_t val) {
|
||||||
|
((uint8_t *)ptr)[0] = (val >> 0) & 0xff;
|
||||||
|
((uint8_t *)ptr)[1] = (val >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t fat12_read_u16(void *ptr) {
|
||||||
|
uint16_t val = 0;
|
||||||
|
val |= (((uint8_t *)ptr)[0] << 0) & 0x00ff;
|
||||||
|
val |= (((uint8_t *)ptr)[1] << 8) & 0xff00;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fat12_set_cluster(void *fat, uint32_t cluster, uint32_t value) {
|
||||||
|
uint32_t offset = (cluster * 3) / 2;
|
||||||
|
if (cluster&1) {
|
||||||
|
((uint8_t *)fat)[offset] = (((uint8_t *)fat)[offset] & 0x0f) | ((value << 4) & 0xf0);
|
||||||
|
((uint8_t *)fat)[offset + 1] = value >> 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
((uint8_t *)fat)[offset] = value;
|
||||||
|
((uint8_t *)fat)[offset + 1] = (((uint8_t *)fat)[offset] & 0xf0) | ((value >> 8) & 0x0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fat12_get_cluster(void *fat, uint32_t cluster) {
|
||||||
|
uint32_t offset = (cluster * 3) / 2;
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
if (cluster&1) {
|
||||||
|
value |= (((uint8_t *)fat)[offset] >> 4) & 0x00f;
|
||||||
|
value |= (((uint8_t *)fat)[offset + 1] << 4) & 0xff0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value |= ((uint8_t *)fat)[offset];
|
||||||
|
value |= (((uint8_t *)fat)[offset + 1] << 8) & 0xf00;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
15
src/io.c
Normal file
15
src/io.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
#ifdef unix
|
||||||
|
ssize_t pang_write(int fd, const void *buf, size_t count) {
|
||||||
|
return write(fd, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t pang_read(int fd, void *buf, size_t count) {
|
||||||
|
return read(fd, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t pang_seek(int fd, off_t offset, int whence) {
|
||||||
|
return lseek(fd, offset, whence);
|
||||||
|
}
|
||||||
|
#endif
|
127
src/mkfat.c
Normal file
127
src/mkfat.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
struct 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];
|
||||||
|
};
|
||||||
|
|
||||||
|
int fat12_mkfs(int fd, uint32_t bytes) {
|
||||||
|
uint8_t mbr[512];
|
||||||
|
const uint16_t sector_size = 512;
|
||||||
|
const uint8_t cluster_size = 8; // 4 kiB cluster sizes match flash erase block size
|
||||||
|
|
||||||
|
// XXX What happens if this is an even multiple of sectors?
|
||||||
|
uint32_t fat_size = 1 + ((((bytes * 3) / sector_size) / cluster_size) / 2);
|
||||||
|
|
||||||
|
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
|
||||||
|
mbr[0x0d] = cluster_size;
|
||||||
|
|
||||||
|
// Reserved sector count (8 sectors, to pad things to 4096-byte boundaries)
|
||||||
|
fat12_write_u16(mbr + 0x0e, cluster_size);
|
||||||
|
|
||||||
|
// Number of FATs (1)
|
||||||
|
mbr[0x10] = 1;
|
||||||
|
|
||||||
|
// Maximum number of root directory entries (16)
|
||||||
|
fat12_write_u16(mbr + 0x11, 32);
|
||||||
|
|
||||||
|
// Total number of 512-byte sectors
|
||||||
|
fat12_write_u16(mbr + 0x13, bytes / sector_size);
|
||||||
|
|
||||||
|
// Type of media (0xf8 == fixed disk)
|
||||||
|
mbr[0x15] = 0xf8;
|
||||||
|
|
||||||
|
// Sectors per FAT
|
||||||
|
fat12_write_u16(mbr + 0x16, fat_size);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
mbr[0x24] = 0x80;
|
||||||
|
|
||||||
|
// Unused
|
||||||
|
mbr[0x25] = 0;
|
||||||
|
|
||||||
|
// Boot signature
|
||||||
|
mbr[0x26] = 0x29;
|
||||||
|
|
||||||
|
// Serial number
|
||||||
|
mbr[0x27] = 0xf0;
|
||||||
|
mbr[0x28] = 0xb0;
|
||||||
|
mbr[0x29] = 0x00;
|
||||||
|
mbr[0x2a] = 0x07;
|
||||||
|
|
||||||
|
// Volume Name
|
||||||
|
memcpy(mbr + 0x2b, "Fomu ", 11);
|
||||||
|
|
||||||
|
// Filesystem
|
||||||
|
memcpy(mbr + 0x36, "FAT12 ", 8);
|
||||||
|
|
||||||
|
// Signature
|
||||||
|
mbr[0xfe] = 0x55;
|
||||||
|
mbr[0xff] = 0xaa;
|
||||||
|
|
||||||
|
// Write MBR to disk
|
||||||
|
if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(mbr, 0, sizeof(mbr));
|
||||||
|
|
||||||
|
// The first two clusters in the FAT are reserved, and must be 0xff
|
||||||
|
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(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
41
tests/test_get_set_cluster.c
Normal file
41
tests/test_get_set_cluster.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "fat12.h"
|
||||||
|
|
||||||
|
static uint8_t sample_fat12[] = {
|
||||||
|
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60,
|
||||||
|
0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14,
|
||||||
|
0xC0, 0x00, 0x0D, 0xE0, 0x00, 0x0F, 0x00, 0x01,
|
||||||
|
0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60,
|
||||||
|
0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF,
|
||||||
|
0x0F, 0x00, 0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t fat12_compare[] = {
|
||||||
|
0xff0, 0xfff, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008,
|
||||||
|
0xfff, 0x00a, 0x014, 0x00c, 0x00d, 0x00e, 0x00f, 0x010,
|
||||||
|
0x011, 0xfff, 0x000, 0xfff, 0x015, 0x016, 0x019, 0xff7,
|
||||||
|
0xff7, 0x01a, 0xfff, 0x000, 0x000, 0xff7, 0x000, 0x000,
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int i;
|
||||||
|
uint8_t generated_fat12[sizeof(sample_fat12)];
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(fat12_compare) / sizeof(*fat12_compare); i++) {
|
||||||
|
uint32_t cluster = fat12_get_cluster(sample_fat12, i);
|
||||||
|
fprintf(stderr, "GET: %2d: %03x (%03x) %s\n", i, cluster, fat12_compare[i], cluster == fat12_compare[i] ? "Ok" : "Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(fat12_compare) / sizeof(*fat12_compare); i++) {
|
||||||
|
fat12_set_cluster(generated_fat12, i, fat12_compare[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(sample_fat12) / sizeof(*sample_fat12); i++) {
|
||||||
|
fprintf(stderr, "PUT: %2d: %02x (%02x) %s\n",
|
||||||
|
i,
|
||||||
|
generated_fat12[i], sample_fat12[i],
|
||||||
|
generated_fat12[i] == sample_fat12[i] ? "Ok" : "Error");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user