2019-06-03 01:57:25 +00:00
|
|
|
#include "fat12.h"
|
2019-06-09 12:32:53 +00:00
|
|
|
#include "fat12-internals.h"
|
|
|
|
#include "io.h"
|
2019-06-03 01:57:25 +00:00
|
|
|
|
2019-06-09 12:32:53 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
struct fat12_partition {
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
};
|
2019-06-09 07:48:07 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-06-03 01:57:25 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-06-10 14:29:21 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-06-03 01:57:25 +00:00
|
|
|
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;
|
2019-06-09 12:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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->fd > 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
part->fd = pang_open(filename, O_RDWR);
|
|
|
|
if (part->fd == -1) {
|
|
|
|
part->fd = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pang_read(part->fd, 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;
|
|
|
|
|
2019-06-10 14:29:21 +00:00
|
|
|
// Move to the root directory
|
|
|
|
part->current_cluster = part->first_offset;
|
|
|
|
|
2019-06-09 12:32:53 +00:00
|
|
|
///
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-06-10 14:29:21 +00:00
|
|
|
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_seek(part->fd, sector * part->sector_size, SEEK_SET);
|
|
|
|
pang_read(part->fd, 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;
|
|
|
|
}
|
|
|
|
|
2019-06-09 12:32:53 +00:00
|
|
|
int fat12_close(struct fat12_partition *part) {
|
|
|
|
if (!part)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (part->fd <= 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (-1 == pang_close(part->fd)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
part->fd = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fat12_free(struct fat12_partition **part) {
|
|
|
|
if (!part)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!*part)
|
|
|
|
return;
|
|
|
|
|
|
|
|
free(*part);
|
|
|
|
*part = NULL;
|
2019-06-03 01:57:25 +00:00
|
|
|
}
|