|
|
|
@ -34,89 +34,68 @@ typedef struct __attribute__((packed)) { |
|
|
|
uint32_t size; |
|
|
|
uint32_t size; |
|
|
|
} fat16_dir_entry_t; |
|
|
|
} fat16_dir_entry_t; |
|
|
|
|
|
|
|
|
|
|
|
#define MAX_INODES 256 |
|
|
|
// Assuming one persistently mounted partition.
|
|
|
|
|
|
|
|
static fat16_bpb_t *bpb = NUL; |
|
|
|
|
|
|
|
static uint32_t data_start; |
|
|
|
|
|
|
|
static uint16_t *fat = NUL; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
typedef struct { |
|
|
|
uint32_t refs; |
|
|
|
fs_node_t base; |
|
|
|
uint16_t first_cluster; |
|
|
|
|
|
|
|
uint32_t size; |
|
|
|
|
|
|
|
uint16_t dir_cluster; |
|
|
|
uint16_t dir_cluster; |
|
|
|
uint16_t dir_index; |
|
|
|
uint16_t dir_index; |
|
|
|
uint8_t removed; |
|
|
|
uint16_t first_cluster; |
|
|
|
} fat16_inode_t; |
|
|
|
} fat16_node_t; |
|
|
|
|
|
|
|
|
|
|
|
static fat16_inode_t inodes[MAX_INODES]; |
|
|
|
#define MAX_NODES 256 |
|
|
|
|
|
|
|
|
|
|
|
static fat16_inode_t *inode_create(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) { |
|
|
|
static fat16_node_t nodes[MAX_NODES]; |
|
|
|
for (uint64_t i = 0; i < MAX_INODES; i++) { |
|
|
|
|
|
|
|
if (!inodes[i].refs) { |
|
|
|
static fs_node_t *node_create(uint16_t dir_cluster, uint16_t dir_index, const char *name, uint8_t is_dir, uint16_t first_cluster, |
|
|
|
inodes[i] = (fat16_inode_t){ |
|
|
|
uint32_t size) { |
|
|
|
.refs = 1, |
|
|
|
for (uint64_t i = 0; i < MAX_NODES; i++) { |
|
|
|
.first_cluster = first_cluster, |
|
|
|
if (!nodes[i].base.refs) { |
|
|
|
.size = size, |
|
|
|
nodes[i].base.type = FAT16; |
|
|
|
.dir_cluster = dir_cluster, |
|
|
|
nodes[i].base.refs = 1; |
|
|
|
.dir_index = dir_index, |
|
|
|
memory_copy(name, FILENAME_SIZE_LIMIT + 1, nodes[i].base.name); |
|
|
|
}; |
|
|
|
nodes[i].base.size = size; |
|
|
|
return &inodes[i]; |
|
|
|
nodes[i].base.is_dir = is_dir; |
|
|
|
|
|
|
|
nodes[i].base.removed = 0; |
|
|
|
|
|
|
|
nodes[i].dir_cluster = dir_cluster; |
|
|
|
|
|
|
|
nodes[i].dir_index = dir_index; |
|
|
|
|
|
|
|
nodes[i].first_cluster = first_cluster; |
|
|
|
|
|
|
|
return (fs_node_t *)&nodes[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static fat16_inode_t *inode_get(uint32_t dir_cluster, uint16_t dir_index) { |
|
|
|
static fs_node_t *node_get(uint32_t dir_cluster, uint16_t dir_index) { |
|
|
|
for (uint64_t i = 0; i < MAX_INODES; i++) { |
|
|
|
for (uint64_t i = 0; i < MAX_NODES; i++) { |
|
|
|
if (inodes[i].refs && inodes[i].dir_cluster == dir_cluster && inodes[i].dir_index == dir_index) { |
|
|
|
if (nodes[i].base.refs && nodes[i].dir_cluster == dir_cluster && nodes[i].dir_index == dir_index) { |
|
|
|
return &inodes[i]; |
|
|
|
return (fs_node_t *)&nodes[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static fat16_inode_t *inode_use(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) { |
|
|
|
static fs_node_t *node_use(uint16_t dir_cluster, uint16_t dir_index, const char *name, uint8_t is_dir, uint16_t first_cluster, |
|
|
|
fat16_inode_t *result = inode_get(dir_cluster, dir_index); |
|
|
|
uint32_t size) { |
|
|
|
|
|
|
|
fs_node_t *result = node_get(dir_cluster, dir_index); |
|
|
|
if (!result) { |
|
|
|
if (!result) { |
|
|
|
result = inode_create(first_cluster, size, dir_cluster, dir_index); |
|
|
|
result = node_create(dir_cluster, dir_index, name, is_dir, first_cluster, size); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
ASSERT(result->refs < UINT32_MAX, "node_use: too many references"); |
|
|
|
result->refs++; |
|
|
|
result->refs++; |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void inode_free(fat16_inode_t *inode) { |
|
|
|
static void node_free(fs_node_t *node) { |
|
|
|
if (inode->refs) { |
|
|
|
if (node->refs) { |
|
|
|
inode->refs--; |
|
|
|
node->refs--; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
|
|
fs_node_t base; |
|
|
|
|
|
|
|
fat16_inode_t *inode; |
|
|
|
|
|
|
|
} fat16_node_t; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static fat16_bpb_t bpb; // Assuming one partition.
|
|
|
|
|
|
|
|
static uint32_t data_start; |
|
|
|
|
|
|
|
static fs_node_t *fs = NUL; |
|
|
|
|
|
|
|
static uint16_t *fat = NUL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *fat16_mount() { // Assuming one partition.
|
|
|
|
|
|
|
|
uint8_t sector[512]; |
|
|
|
|
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR, 1, §or); |
|
|
|
|
|
|
|
memory_copy(sector + 11, sizeof(fat16_bpb_t), &bpb); |
|
|
|
|
|
|
|
data_start = FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.sectors_per_fat * bpb.fats_count + |
|
|
|
|
|
|
|
(bpb.root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE; |
|
|
|
|
|
|
|
fat16_node_t *node = memory_allocate(sizeof(fat16_node_t)); |
|
|
|
|
|
|
|
node->base.type = FAT16; |
|
|
|
|
|
|
|
node->base.name[0] = '/'; |
|
|
|
|
|
|
|
node->base.size = sizeof(fat16_dir_entry_t) * bpb.root_entry_count; |
|
|
|
|
|
|
|
node->base.is_dir = 1; |
|
|
|
|
|
|
|
node->inode = inode_use(0, node->base.size, 0, UINT16_MAX); |
|
|
|
|
|
|
|
if (!node->inode) { |
|
|
|
|
|
|
|
memory_free(node); |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return fs = (fs_node_t *)node; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void to_8_3(const char *name, char *output) { |
|
|
|
static void to_8_3(const char *name, char *output) { |
|
|
|
memory_set(' ', 11, output); |
|
|
|
memory_set(' ', 11, output); |
|
|
|
output[11] = '\0'; |
|
|
|
output[11] = '\0'; |
|
|
|
@ -150,17 +129,35 @@ static void from_8_3(const char *name, const char *extension, char *output) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ensure_bpb() { |
|
|
|
|
|
|
|
if (bpb) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t sector[512]; |
|
|
|
|
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR, 1, §or); |
|
|
|
|
|
|
|
bpb = memory_allocate(sizeof(fat16_bpb_t)); |
|
|
|
|
|
|
|
memory_copy(sector + 11, sizeof(fat16_bpb_t), bpb); |
|
|
|
|
|
|
|
data_start = FIRST_PARTITION_SECTOR + bpb->reserved_sectors + bpb->sectors_per_fat * bpb->fats_count + |
|
|
|
|
|
|
|
(bpb->root_entry_count * sizeof(fat16_dir_entry_t) + SECTOR_SIZE - 1) / SECTOR_SIZE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ensure_fat() { |
|
|
|
static void ensure_fat() { |
|
|
|
ASSERT(bpb.sectors_per_fat < 256, "ensure_fat: big FAT not implemented") |
|
|
|
if (fat) { |
|
|
|
if (!fat) { |
|
|
|
return; |
|
|
|
fat = memory_allocate(bpb.sectors_per_fat * SECTOR_SIZE); |
|
|
|
|
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ensure_bpb(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT(bpb->sectors_per_fat < 256, "ensure_fat: big FAT not implemented"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fat = memory_allocate(bpb->sectors_per_fat * SECTOR_SIZE); |
|
|
|
|
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors, (uint8_t)bpb->sectors_per_fat, fat); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t allocate_cluster() { |
|
|
|
static uint16_t allocate_cluster() { |
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
for (uint16_t i = 2; i < bpb.sectors_per_fat * SECTOR_SIZE / 2; i++) { |
|
|
|
for (uint16_t i = 2; i < bpb->sectors_per_fat * SECTOR_SIZE / 2; i++) { |
|
|
|
if (fat[i] == 0x0000) { |
|
|
|
if (fat[i] == 0x0000) { |
|
|
|
fat[i] = 0xFFFF; |
|
|
|
fat[i] = 0xFFFF; |
|
|
|
return i; |
|
|
|
return i; |
|
|
|
@ -170,15 +167,18 @@ static uint16_t allocate_cluster() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void flush_fat() { |
|
|
|
static void flush_fat() { |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors, (uint8_t)bpb->sectors_per_fat, fat); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint16_t read_directory(uint16_t dir_cluster, fat16_dir_entry_t **entries) { |
|
|
|
static uint16_t read_directory(uint16_t dir_cluster, fat16_dir_entry_t **entries) { |
|
|
|
|
|
|
|
ensure_bpb(); |
|
|
|
|
|
|
|
|
|
|
|
if (!dir_cluster) { |
|
|
|
if (!dir_cluster) { |
|
|
|
uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE); |
|
|
|
uint8_t sectors = (uint8_t)((sizeof(fat16_dir_entry_t) * bpb->root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE); |
|
|
|
*entries = memory_allocate(sectors * SECTOR_SIZE); |
|
|
|
*entries = memory_allocate(sectors * SECTOR_SIZE); |
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, sectors, *entries); |
|
|
|
ata_read_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors + bpb->fats_count * bpb->sectors_per_fat, sectors, *entries); |
|
|
|
return bpb.root_entry_count; |
|
|
|
return bpb->root_entry_count; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
|
|
|
|
@ -188,19 +188,19 @@ static uint16_t read_directory(uint16_t dir_cluster, fat16_dir_entry_t **entries |
|
|
|
cluster_count++; |
|
|
|
cluster_count++; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
} |
|
|
|
} |
|
|
|
*entries = memory_allocate(cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE); |
|
|
|
*entries = memory_allocate(cluster_count * bpb->sectors_per_cluster * SECTOR_SIZE); |
|
|
|
|
|
|
|
|
|
|
|
uint8_t *chunk = (uint8_t *)*entries; |
|
|
|
uint8_t *chunk = (uint8_t *)*entries; |
|
|
|
next_cluster = dir_cluster; |
|
|
|
next_cluster = dir_cluster; |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
while (next_cluster < 0xFFF8) { |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk); |
|
|
|
ata_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, chunk); |
|
|
|
chunk += bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
chunk += bpb->sectors_per_cluster * SECTOR_SIZE; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
} |
|
|
|
} |
|
|
|
return cluster_count * bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
return cluster_count * bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
return (uint16_t)-1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) { |
|
|
|
static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t index) { |
|
|
|
@ -210,38 +210,30 @@ static fs_node_t *open_entry(uint16_t dir_cluster, const fat16_dir_entry_t *entr |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_node_t *result = memory_allocate(sizeof(fat16_node_t)); |
|
|
|
char name[FILENAME_SIZE_LIMIT + 1]; |
|
|
|
result->base.type = FAT16; |
|
|
|
from_8_3(entry->name, entry->ext, name); |
|
|
|
from_8_3(entry->name, entry->ext, result->base.name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result->base.size = entry->size; |
|
|
|
|
|
|
|
result->base.is_dir = entry->attributes & ATTRIBUTE_SUBDIRECTORY; |
|
|
|
|
|
|
|
result->inode = inode_use(entry->first_cluster, entry->size, dir_cluster, index); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!result->inode) { |
|
|
|
|
|
|
|
memory_free(result); |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (fs_node_t *)result; |
|
|
|
return node_use(dir_cluster, index, name, entry->attributes & ATTRIBUTE_SUBDIRECTORY, entry->first_cluster, entry->size); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t count) { |
|
|
|
static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entries, uint16_t count) { |
|
|
|
ASSERT((count * sizeof(fat16_dir_entry_t)) % (bpb.sectors_per_cluster * SECTOR_SIZE) == 0, |
|
|
|
ensure_bpb(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ASSERT((count * sizeof(fat16_dir_entry_t)) % (bpb->sectors_per_cluster * SECTOR_SIZE) == 0, |
|
|
|
"write_directory: entries must be aligned to clusters"); |
|
|
|
"write_directory: entries must be aligned to clusters"); |
|
|
|
|
|
|
|
|
|
|
|
if (!dir_cluster) { |
|
|
|
if (!dir_cluster) { |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors + bpb.fats_count * bpb.sectors_per_fat, |
|
|
|
ata_write_sectors(FIRST_PARTITION_SECTOR + bpb->reserved_sectors + bpb->fats_count * bpb->sectors_per_fat, |
|
|
|
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb.root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries); |
|
|
|
(uint8_t)((sizeof(fat16_dir_entry_t) * bpb->root_entry_count + SECTOR_SIZE - 1) / SECTOR_SIZE), entries); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
|
|
|
|
uint8_t *chunk = (uint8_t *)entries; |
|
|
|
uint8_t *chunk = (uint8_t *)entries; |
|
|
|
uint16_t next_cluster = dir_cluster; |
|
|
|
uint16_t next_cluster = dir_cluster; |
|
|
|
while (count) { |
|
|
|
while (count) { |
|
|
|
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, chunk); |
|
|
|
ata_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, chunk); |
|
|
|
chunk += bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
chunk += bpb->sectors_per_cluster * SECTOR_SIZE; |
|
|
|
count -= bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
count -= bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
if (count && fat[next_cluster] >= 0xFFF8) { |
|
|
|
if (count && fat[next_cluster] >= 0xFFF8) { |
|
|
|
fat[next_cluster] = allocate_cluster(); |
|
|
|
fat[next_cluster] = allocate_cluster(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -251,16 +243,18 @@ static void write_directory(uint16_t dir_cluster, const fat16_dir_entry_t *entri |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t flags) { |
|
|
|
fs_node_t *fat16_open_root() { |
|
|
|
if (directory->type != FAT16 || !directory->is_dir) { |
|
|
|
ensure_bpb(); |
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
return node_use(0, UINT16_MAX, "", 1, 0, sizeof(fat16_dir_entry_t) * bpb->root_entry_count); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (((fat16_node_t *)directory)->inode->removed) { |
|
|
|
fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t flags) { |
|
|
|
|
|
|
|
if (!directory || directory->type != FAT16 || !directory->is_dir || directory->removed) { |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster; |
|
|
|
uint16_t dir_cluster = ((fat16_node_t *)directory)->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
char name_8_3[12]; |
|
|
|
char name_8_3[12]; |
|
|
|
to_8_3(name, name_8_3); |
|
|
|
to_8_3(name, name_8_3); |
|
|
|
@ -295,7 +289,7 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
uint16_t new_entries_count = entries_count + bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
uint16_t new_entries_count = entries_count + bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t); |
|
|
|
fat16_dir_entry_t *new_entries = memory_allocate(new_entries_count * sizeof(fat16_dir_entry_t)); |
|
|
|
fat16_dir_entry_t *new_entries = memory_allocate(new_entries_count * sizeof(fat16_dir_entry_t)); |
|
|
|
memory_copy(entries, entries_count * sizeof(fat16_dir_entry_t), new_entries); |
|
|
|
memory_copy(entries, entries_count * sizeof(fat16_dir_entry_t), new_entries); |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
@ -309,14 +303,14 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t |
|
|
|
if (flags & OPEN_DIRECTORY && !(flags & OPEN_FILE)) { |
|
|
|
if (flags & OPEN_DIRECTORY && !(flags & OPEN_FILE)) { |
|
|
|
entries[index].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
entries[index].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
entries[index].first_cluster = allocate_cluster(); |
|
|
|
entries[index].first_cluster = allocate_cluster(); |
|
|
|
fat16_dir_entry_t *inner_entries = memory_allocate(bpb.sectors_per_cluster * SECTOR_SIZE); |
|
|
|
fat16_dir_entry_t *inner_entries = memory_allocate(bpb->sectors_per_cluster * SECTOR_SIZE); |
|
|
|
memory_copy(". ", 11, inner_entries[0].name); |
|
|
|
memory_copy(". ", 11, inner_entries[0].name); |
|
|
|
inner_entries[0].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
inner_entries[0].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
inner_entries[0].first_cluster = entries[index].first_cluster; |
|
|
|
inner_entries[0].first_cluster = entries[index].first_cluster; |
|
|
|
memory_copy(".. ", 11, inner_entries[1].name); |
|
|
|
memory_copy(".. ", 11, inner_entries[1].name); |
|
|
|
inner_entries[1].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
inner_entries[1].attributes = ATTRIBUTE_SUBDIRECTORY; |
|
|
|
inner_entries[1].first_cluster = dir_cluster; |
|
|
|
inner_entries[1].first_cluster = dir_cluster; |
|
|
|
write_directory(entries[index].first_cluster, inner_entries, bpb.sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t)); |
|
|
|
write_directory(entries[index].first_cluster, inner_entries, bpb->sectors_per_cluster * SECTOR_SIZE / sizeof(fat16_dir_entry_t)); |
|
|
|
memory_free(inner_entries); |
|
|
|
memory_free(inner_entries); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -343,15 +337,11 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags) { |
|
|
|
fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t flags) { |
|
|
|
if (directory->type != FAT16 || !directory->is_dir) { |
|
|
|
if (!directory || directory->type != FAT16 || !directory->is_dir || directory->removed) { |
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (((fat16_node_t *)directory)->inode->removed) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
return NUL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster; |
|
|
|
uint16_t dir_cluster = ((fat16_node_t *)directory)->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
uint16_t entries_count = read_directory(dir_cluster, &entries); |
|
|
|
uint16_t entries_count = read_directory(dir_cluster, &entries); |
|
|
|
@ -367,7 +357,7 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t fl |
|
|
|
ei++; |
|
|
|
ei++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *result = open_entry(((fat16_node_t *)directory)->inode->first_cluster, entries, ei); |
|
|
|
fs_node_t *result = open_entry(dir_cluster, entries, ei); |
|
|
|
|
|
|
|
|
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
|
|
|
|
@ -390,36 +380,33 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t fl |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fs_node_t *fat16_open_again(const fs_node_t *source) { |
|
|
|
fs_node_t *fat16_open_again(fs_node_t *source) { |
|
|
|
fs_node_t *result = memory_allocate(sizeof(fat16_node_t)); |
|
|
|
ASSERT(source->refs < UINT32_MAX, "fat16_open_again: too many references"); |
|
|
|
memory_copy(source, sizeof(fat16_node_t), result); |
|
|
|
source->refs++; |
|
|
|
((fat16_node_t *)result)->inode->refs++; |
|
|
|
return source; |
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to) { |
|
|
|
uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void *to) { |
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
if (!file || file->type != FAT16 || file->is_dir) { |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
return (uint64_t)-1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->inode->removed) { |
|
|
|
if (file->removed) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (offset >= fat_file->inode->size) { |
|
|
|
if (offset >= file->size) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (offset + bytes >= fat_file->inode->size) { |
|
|
|
if (offset + bytes >= file->size) { |
|
|
|
bytes = fat_file->inode->size - offset; |
|
|
|
bytes = file->size - offset; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
|
|
|
|
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
uint32_t cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; |
|
|
|
uint32_t next_cluster = fat_file->inode->first_cluster; |
|
|
|
uint32_t next_cluster = ((fat16_node_t *)file)->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
while (offset >= cluster_size) { |
|
|
|
while (offset >= cluster_size) { |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
@ -431,7 +418,7 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void |
|
|
|
uint8_t *cursor = to; |
|
|
|
uint8_t *cursor = to; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t *tmp = memory_allocate(cluster_size); |
|
|
|
uint8_t *tmp = memory_allocate(cluster_size); |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp); |
|
|
|
ata_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); |
|
|
|
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset; |
|
|
|
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset; |
|
|
|
memory_copy(tmp + offset, prefix_size, cursor); |
|
|
|
memory_copy(tmp + offset, prefix_size, cursor); |
|
|
|
bytes -= prefix_size; |
|
|
|
bytes -= prefix_size; |
|
|
|
@ -440,7 +427,7 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
|
|
|
|
|
|
|
|
while (bytes >= cluster_size) { |
|
|
|
while (bytes >= cluster_size) { |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, cursor); |
|
|
|
ata_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, cursor); |
|
|
|
bytes -= cluster_size; |
|
|
|
bytes -= cluster_size; |
|
|
|
readden += cluster_size; |
|
|
|
readden += cluster_size; |
|
|
|
cursor += cluster_size; |
|
|
|
cursor += cluster_size; |
|
|
|
@ -448,7 +435,7 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (bytes) { |
|
|
|
if (bytes) { |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp); |
|
|
|
ata_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); |
|
|
|
memory_copy(tmp, bytes, cursor); |
|
|
|
memory_copy(tmp, bytes, cursor); |
|
|
|
readden += bytes; |
|
|
|
readden += bytes; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -459,24 +446,24 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes) { |
|
|
|
uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes) { |
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
if (!file || file->type != FAT16 || file->is_dir) { |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
return (uint64_t)-1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->inode->removed) { |
|
|
|
if (file->removed) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
|
|
|
|
|
|
|
|
if (!fat_file->inode->first_cluster) { |
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
fat_file->inode->first_cluster = allocate_cluster(); |
|
|
|
|
|
|
|
|
|
|
|
if (!fat_file->first_cluster) { |
|
|
|
|
|
|
|
fat_file->first_cluster = allocate_cluster(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
uint32_t cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; |
|
|
|
uint32_t next_cluster = fat_file->inode->first_cluster; |
|
|
|
uint32_t next_cluster = fat_file->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
uint32_t allocated = cluster_size; |
|
|
|
uint32_t allocated = cluster_size; |
|
|
|
while (allocated < offset + bytes) { |
|
|
|
while (allocated < offset + bytes) { |
|
|
|
@ -489,8 +476,8 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ |
|
|
|
|
|
|
|
|
|
|
|
flush_fat(); |
|
|
|
flush_fat(); |
|
|
|
|
|
|
|
|
|
|
|
cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; |
|
|
|
next_cluster = fat_file->inode->first_cluster; |
|
|
|
next_cluster = fat_file->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
while (offset >= cluster_size) { |
|
|
|
while (offset >= cluster_size) { |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
@ -502,17 +489,17 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ |
|
|
|
const uint8_t *cursor = from; |
|
|
|
const uint8_t *cursor = from; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t *tmp = memory_allocate(cluster_size); |
|
|
|
uint8_t *tmp = memory_allocate(cluster_size); |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp); |
|
|
|
ata_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); |
|
|
|
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset; |
|
|
|
uint32_t prefix_size = bytes <= cluster_size - offset ? bytes : cluster_size - offset; |
|
|
|
memory_copy(cursor, prefix_size, tmp + offset); |
|
|
|
memory_copy(cursor, prefix_size, tmp + offset); |
|
|
|
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp); |
|
|
|
ata_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); |
|
|
|
bytes -= prefix_size; |
|
|
|
bytes -= prefix_size; |
|
|
|
written += prefix_size; |
|
|
|
written += prefix_size; |
|
|
|
cursor += prefix_size; |
|
|
|
cursor += prefix_size; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
next_cluster = fat[next_cluster]; |
|
|
|
|
|
|
|
|
|
|
|
while (bytes >= cluster_size) { |
|
|
|
while (bytes >= cluster_size) { |
|
|
|
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, cursor); |
|
|
|
ata_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, cursor); |
|
|
|
bytes -= cluster_size; |
|
|
|
bytes -= cluster_size; |
|
|
|
written += cluster_size; |
|
|
|
written += cluster_size; |
|
|
|
cursor += cluster_size; |
|
|
|
cursor += cluster_size; |
|
|
|
@ -520,22 +507,22 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (bytes) { |
|
|
|
if (bytes) { |
|
|
|
ata_read_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp); |
|
|
|
ata_read_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); |
|
|
|
memory_copy(cursor, bytes, tmp); |
|
|
|
memory_copy(cursor, bytes, tmp); |
|
|
|
ata_write_sectors(data_start + bpb.sectors_per_cluster * (next_cluster - 2), bpb.sectors_per_cluster, tmp); |
|
|
|
ata_write_sectors(data_start + bpb->sectors_per_cluster * (next_cluster - 2), bpb->sectors_per_cluster, tmp); |
|
|
|
written += bytes; |
|
|
|
written += bytes; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
memory_free(tmp); |
|
|
|
memory_free(tmp); |
|
|
|
|
|
|
|
|
|
|
|
if (offset + written > fat_file->inode->size) { |
|
|
|
if (offset + written > file->size) { |
|
|
|
fat_file->inode->size = offset + written; |
|
|
|
file->size = offset + written; |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
uint16_t entries_count = read_directory(fat_file->inode->dir_cluster, &entries); |
|
|
|
uint16_t entries_count = read_directory(fat_file->dir_cluster, &entries); |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster; |
|
|
|
entries[fat_file->dir_index].first_cluster = fat_file->first_cluster; |
|
|
|
entries[fat_file->inode->dir_index].size = fat_file->inode->size; |
|
|
|
entries[fat_file->dir_index].size = file->size; |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries, entries_count); |
|
|
|
write_directory(fat_file->dir_cluster, entries, entries_count); |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -543,13 +530,11 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
if (!file || file->type != FAT16 || file->is_dir) { |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->base.type != FAT16 || fat_file->base.is_dir) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
return (uint64_t)-1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->inode->removed) { |
|
|
|
if (file->removed) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -562,9 +547,11 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
memory_free(tmp); |
|
|
|
memory_free(tmp); |
|
|
|
return written == (uint64_t)-1 ? (uint64_t)-1 : file->size + written; |
|
|
|
return written == (uint64_t)-1 ? (uint64_t)-1 : file->size + written; |
|
|
|
} else if (file->size > size) { |
|
|
|
} else if (file->size > size) { |
|
|
|
uint32_t cluster_size = bpb.sectors_per_cluster * SECTOR_SIZE; |
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t cluster_size = bpb->sectors_per_cluster * SECTOR_SIZE; |
|
|
|
uint32_t prev_cluster = 0; |
|
|
|
uint32_t prev_cluster = 0; |
|
|
|
uint32_t next_cluster = fat_file->inode->first_cluster; |
|
|
|
uint32_t next_cluster = fat_file->first_cluster; |
|
|
|
|
|
|
|
|
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
uint32_t allocated = 0; |
|
|
|
uint32_t allocated = 0; |
|
|
|
@ -576,7 +563,7 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
if (prev_cluster) { |
|
|
|
if (prev_cluster) { |
|
|
|
fat[prev_cluster] = 0xFFFF; |
|
|
|
fat[prev_cluster] = 0xFFFF; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
fat_file->inode->first_cluster = 0; |
|
|
|
fat_file->first_cluster = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
do { |
|
|
|
do { |
|
|
|
uint32_t swap = fat[next_cluster]; |
|
|
|
uint32_t swap = fat[next_cluster]; |
|
|
|
@ -585,12 +572,12 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
} while (next_cluster < 0xFFF8); |
|
|
|
} while (next_cluster < 0xFFF8); |
|
|
|
flush_fat(); |
|
|
|
flush_fat(); |
|
|
|
|
|
|
|
|
|
|
|
fat_file->inode->size = size; |
|
|
|
file->size = size; |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
uint16_t entries_count = read_directory(fat_file->inode->dir_cluster, &entries); |
|
|
|
uint16_t entries_count = read_directory(fat_file->dir_cluster, &entries); |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = fat_file->inode->first_cluster; |
|
|
|
entries[fat_file->dir_index].first_cluster = fat_file->first_cluster; |
|
|
|
entries[fat_file->inode->dir_index].size = fat_file->inode->size; |
|
|
|
entries[fat_file->dir_index].size = file->size; |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries, entries_count); |
|
|
|
write_directory(fat_file->dir_cluster, entries, entries_count); |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
|
|
|
|
return size; |
|
|
|
return size; |
|
|
|
@ -599,19 +586,19 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint64_t fat16_remove(fs_node_t *file) { |
|
|
|
uint64_t fat16_remove(fs_node_t *file) { |
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
if (!file || file->type != FAT16) { |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->base.type != FAT16) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
return (uint64_t)-1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->inode->removed) { |
|
|
|
if (file->removed) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fat16_node_t *fat_file = (fat16_node_t *)file; |
|
|
|
|
|
|
|
|
|
|
|
if (file->is_dir) { |
|
|
|
if (file->is_dir) { |
|
|
|
fat16_dir_entry_t *subentries; |
|
|
|
fat16_dir_entry_t *subentries; |
|
|
|
uint16_t subentries_count = read_directory(fat_file->inode->first_cluster, &subentries); |
|
|
|
uint16_t subentries_count = read_directory(fat_file->first_cluster, &subentries); |
|
|
|
uint16_t ei = 0, vi = 0; |
|
|
|
uint16_t ei = 0, vi = 0; |
|
|
|
while (ei < subentries_count && subentries[ei].name[0]) { |
|
|
|
while (ei < subentries_count && subentries[ei].name[0]) { |
|
|
|
if ((uint8_t)subentries[ei].name[0] != 0xE5 && (uint8_t)subentries[ei].attributes != 0x0F) { |
|
|
|
if ((uint8_t)subentries[ei].name[0] != 0xE5 && (uint8_t)subentries[ei].attributes != 0x0F) { |
|
|
|
@ -625,11 +612,11 @@ uint64_t fat16_remove(fs_node_t *file) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat_file->inode->removed = 1; |
|
|
|
file->removed = 1; |
|
|
|
|
|
|
|
|
|
|
|
if (fat_file->inode->first_cluster) { |
|
|
|
if (fat_file->first_cluster) { |
|
|
|
ensure_fat(); |
|
|
|
ensure_fat(); |
|
|
|
uint64_t next_cluster = fat_file->inode->first_cluster; |
|
|
|
uint64_t next_cluster = fat_file->first_cluster; |
|
|
|
do { |
|
|
|
do { |
|
|
|
uint32_t swap = fat[next_cluster]; |
|
|
|
uint32_t swap = fat[next_cluster]; |
|
|
|
fat[next_cluster] = 0; |
|
|
|
fat[next_cluster] = 0; |
|
|
|
@ -639,11 +626,11 @@ uint64_t fat16_remove(fs_node_t *file) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
fat16_dir_entry_t *entries; |
|
|
|
uint16_t entries_count = read_directory(fat_file->inode->dir_cluster, &entries); |
|
|
|
uint16_t entries_count = read_directory(fat_file->dir_cluster, &entries); |
|
|
|
entries[fat_file->inode->dir_index].name[0] = 0xE5; |
|
|
|
entries[fat_file->dir_index].name[0] = 0xE5; |
|
|
|
entries[fat_file->inode->dir_index].first_cluster = 0; |
|
|
|
entries[fat_file->dir_index].first_cluster = 0; |
|
|
|
entries[fat_file->inode->dir_index].size = 0; |
|
|
|
entries[fat_file->dir_index].size = 0; |
|
|
|
write_directory(fat_file->inode->dir_cluster, entries, entries_count); |
|
|
|
write_directory(fat_file->dir_cluster, entries, entries_count); |
|
|
|
memory_free(entries); |
|
|
|
memory_free(entries); |
|
|
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
@ -656,6 +643,10 @@ typedef struct { |
|
|
|
} fat16_file_stream_t; |
|
|
|
} fat16_file_stream_t; |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t bytes) { |
|
|
|
static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t bytes) { |
|
|
|
|
|
|
|
if (!self) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
uint64_t written = fat16_write(ffs->node, ffs->offset, from, bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes); |
|
|
|
uint64_t written = fat16_write(ffs->node, ffs->offset, from, bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes); |
|
|
|
if (written != (uint64_t)-1) { |
|
|
|
if (written != (uint64_t)-1) { |
|
|
|
@ -665,6 +656,10 @@ static uint64_t file_stream_write(stream_t *self, const char *from, uint64_t byt |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
|
|
|
|
if (!self) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
uint64_t readden = fat16_read(ffs->node, ffs->offset, max > UINT32_MAX ? UINT32_MAX : (uint32_t)max, to); |
|
|
|
uint64_t readden = fat16_read(ffs->node, ffs->offset, max > UINT32_MAX ? UINT32_MAX : (uint32_t)max, to); |
|
|
|
if (readden != (uint64_t)-1) { |
|
|
|
if (readden != (uint64_t)-1) { |
|
|
|
@ -674,6 +669,10 @@ static uint64_t file_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t file_stream_truncate(stream_t *self, uint64_t size) { |
|
|
|
static uint64_t file_stream_truncate(stream_t *self, uint64_t size) { |
|
|
|
|
|
|
|
if (!self) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
uint64_t resized = fat16_truncate(ffs->node, size > UINT32_MAX ? UINT32_MAX : (uint32_t)size); |
|
|
|
uint64_t resized = fat16_truncate(ffs->node, size > UINT32_MAX ? UINT32_MAX : (uint32_t)size); |
|
|
|
if (resized != (uint64_t)-1 && resized < ffs->offset) { |
|
|
|
if (resized != (uint64_t)-1 && resized < ffs->offset) { |
|
|
|
@ -683,6 +682,10 @@ static uint64_t file_stream_truncate(stream_t *self, uint64_t size) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void file_stream_close(stream_t *self) { |
|
|
|
static void file_stream_close(stream_t *self) { |
|
|
|
|
|
|
|
if (!self) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
fat16_file_stream_t *ffs = (fat16_file_stream_t *)self; |
|
|
|
fat16_close(ffs->node); |
|
|
|
fat16_close(ffs->node); |
|
|
|
memory_free(self); |
|
|
|
memory_free(self); |
|
|
|
@ -700,6 +703,10 @@ static uint64_t directory_stream_write(__attribute__((unused)) stream_t *self, _ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
static uint64_t directory_stream_read(stream_t *self, uint64_t max, char *to) { |
|
|
|
|
|
|
|
if (!self) { |
|
|
|
|
|
|
|
return (uint64_t)-1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; |
|
|
|
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; |
|
|
|
fs_node_t *node = fat16_open_at(fds->node, fds->index++, OPEN_FILE | OPEN_DIRECTORY); |
|
|
|
fs_node_t *node = fat16_open_at(fds->node, fds->index++, OPEN_FILE | OPEN_DIRECTORY); |
|
|
|
if (!node) { |
|
|
|
if (!node) { |
|
|
|
@ -717,12 +724,20 @@ static uint64_t directory_stream_truncate(__attribute__((unused)) stream_t *self |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void directory_stream_close(stream_t *self) { |
|
|
|
static void directory_stream_close(stream_t *self) { |
|
|
|
|
|
|
|
if (!self) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; |
|
|
|
fat16_directory_stream_t *fds = (fat16_directory_stream_t *)self; |
|
|
|
fat16_close(fds->node); |
|
|
|
fat16_close(fds->node); |
|
|
|
memory_free(self); |
|
|
|
memory_free(self); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
stream_t *fat16_open_stream(const fs_node_t *source) { |
|
|
|
stream_t *fat16_open_stream(fs_node_t *source) { |
|
|
|
|
|
|
|
if (!source) { |
|
|
|
|
|
|
|
return NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!source->is_dir) { |
|
|
|
if (!source->is_dir) { |
|
|
|
fat16_file_stream_t *result = memory_allocate(sizeof(fat16_file_stream_t)); |
|
|
|
fat16_file_stream_t *result = memory_allocate(sizeof(fat16_file_stream_t)); |
|
|
|
result->stream.read = file_stream_read; |
|
|
|
result->stream.read = file_stream_read; |
|
|
|
@ -745,24 +760,9 @@ stream_t *fat16_open_stream(const fs_node_t *source) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void fat16_close(fs_node_t *node) { |
|
|
|
void fat16_close(fs_node_t *node) { |
|
|
|
if (node->type != FAT16 || node == fs) { |
|
|
|
if (!node || node->type != FAT16) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
inode_free(((fat16_node_t *)node)->inode); |
|
|
|
|
|
|
|
memory_free(node); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void fat16_unmount(fs_node_t *node) { |
|
|
|
|
|
|
|
if (node->type != FAT16 || node != fs) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
inode_free(((fat16_node_t *)node)->inode); |
|
|
|
|
|
|
|
memory_free(node); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (fat) { |
|
|
|
|
|
|
|
memory_free(fat); |
|
|
|
|
|
|
|
fat = NUL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fs = NUL; |
|
|
|
node_free(node); |
|
|
|
} |
|
|
|
} |
|
|
|
|