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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user