#include "fat12.h" #include "fat12-internals.h" #include "io.h" #include struct fat12_partition { struct pang_io *io; // Number of bytes in a sector (512) uint32_t sector_size; uint8_t sector_buffer[512]; // These units are "sectors" uint32_t fat_offset; uint32_t fat_size; uint32_t root_offset; uint32_t first_offset; uint32_t cluster_size; // These are in single-unit quantities uint32_t root_entries; uint32_t cluster_count; uint32_t cluster_bytes; uint32_t sector_count; // Used for traversing directories uint32_t current_cluster; }; 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) { ((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_write_u32(void *ptr, uint32_t val) { ((uint8_t *)ptr)[0] = (val >> 0) & 0xff; ((uint8_t *)ptr)[1] = (val >> 8) & 0xff; ((uint8_t *)ptr)[2] = (val >> 16) & 0xff; ((uint8_t *)ptr)[3] = (val >> 24) & 0xff; } uint32_t fat12_read_u32(void *ptr) { uint16_t val = 0; val |= (((uint8_t *)ptr)[0] << 0) & 0x000000ff; val |= (((uint8_t *)ptr)[1] << 8) & 0x0000ff00; val |= (((uint8_t *)ptr)[2] << 16) & 0x00ff0000; val |= (((uint8_t *)ptr)[3] << 24) & 0xff000000; 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; } struct fat12_partition *fat12_alloc(void) { struct fat12_partition *part = malloc(sizeof(struct fat12_partition)); memset(part, 0, sizeof(*part)); return part; } int fat12_open(struct fat12_partition *part, const char *filename) { if (!part) return -1; if (part->io) return -1; part->io = pang_open(filename); if (!part->io) return -1; if (pang_read(part->io, 0, part->sector_buffer, sizeof(part->sector_buffer)) != sizeof(part->sector_buffer)) return -1; part->sector_size = fat12_read_u16(part->sector_buffer + 0x0b); // These are in single-unit quantities part->root_entries = fat12_read_u16(part->sector_buffer + 0x11); part->sector_count = fat12_read_u16(part->sector_buffer + 0x13); // These units are "sectors" part->fat_offset = fat12_read_u16(part->sector_buffer + 0x0e); part->fat_size = fat12_read_u16(part->sector_buffer + 0x16); part->root_offset = part->fat_offset + part->fat_size; part->first_offset = part->root_offset + (part->root_entries * sizeof(struct fat_directory_entry)) / part->sector_size; part->cluster_size = fat12_read_u8(part->sector_buffer + 0x0d); uint32_t bytes = (part->sector_count - part->first_offset) * part->sector_size; part->cluster_count = bytes / part->sector_size / part->cluster_size; part->cluster_bytes = (part->cluster_count * 3) / 2; // Move to the root directory part->current_cluster = part->first_offset; /// fprintf(stderr, "part->sector_size: %d\n", part->sector_size); // These are in single-unit quantities fprintf(stderr, "part->root_entries: %d\n", part->root_entries); fprintf(stderr, "part->sector_count: %d\n", part->sector_count); // These units are "sectors" fprintf(stderr, "part->fat_offset: %d\n", part->fat_offset); fprintf(stderr, "part->fat_size: %d\n", part->fat_size); fprintf(stderr, "part->root_offset: %d\n", part->root_offset); fprintf(stderr, "part->first_offset: %d\n", part->first_offset); fprintf(stderr, "part->cluster_size: %d\n", part->cluster_size); fprintf(stderr, "part->cluster_count: %d\n", part->cluster_count); fprintf(stderr, "part->cluster_bytes: %d\n", part->cluster_bytes); fprintf(stderr, "data_bytes: %d\n", bytes); /// return 0; } static int fat12_ls_foreach_sector(struct fat12_partition *part, uint32_t sector, uint32_t count, void *data, int (*callback)(void *data, const struct fat12_dirent *dirent)) { struct fat12_dirent dirent; uint8_t buf[part->sector_size]; uint32_t offset; pang_read(part->io, sector * part->sector_size, buf, sizeof(buf)); for (offset = 0; offset < count; offset++) { struct fat_directory_entry *entry = &((struct fat_directory_entry *)buf)[offset]; memset(&dirent, 0, sizeof(dirent)); memcpy(dirent.filename, entry->file_name, 8); memcpy(dirent.filename + 8, entry->extension, 3); dirent.first_cluster = fat12_read_u16(&entry->first_cluster); dirent.size = fat12_read_u32(&entry->file_size); if ((entry->file_name[0] != 0xe5) && (entry->file_name[0] != 0x00)) callback(data, &dirent); } return 0; } int fat12_ls_foreach(struct fat12_partition *part, uint32_t dir_cluster, void *data, int (*callback)(void *data, const struct fat12_dirent *dirent)) { uint32_t sector; if (dir_cluster < 2) { sector = part->root_offset; uint32_t dir_entries; uint32_t max_entries = part->root_entries; uint32_t entries_per_sector = part->sector_size / sizeof(struct fat_directory_entry); uint32_t loop = 0; for (dir_entries = 0; dir_entries < max_entries; dir_entries += entries_per_sector) { uint32_t entries_to_list = entries_per_sector; if (max_entries - dir_entries < entries_to_list) entries_to_list = max_entries - dir_entries; fat12_ls_foreach_sector(part, part->root_offset + loop++, entries_to_list, data, callback); } } else { sector = dir_cluster * part->cluster_size + part->first_offset; while (dir_cluster > 1 && dir_cluster < 0xff0) { // dir_cluster = fat12_get_cluster(part->fd, dir_cluster); } } return 0; } int fat12_close(struct fat12_partition *part) { if (!part) return -1; if (-1 == pang_close(&part->io)) { return -1; } return 0; } void fat12_free(struct fat12_partition **part) { if (!part) return; if (!*part) return; if ((*part)->io) fat12_close(*part); free(*part); *part = NULL; }