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