|
|
|
@ -16,7 +16,7 @@ void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr); |
|
|
|
|
uint32_t find_bs(const BLOCKDEV* dev); |
|
|
|
|
|
|
|
|
|
/** Get cluster's starting address */ |
|
|
|
|
uint32_t clu_start(const FAT16* fat, const uint16_t cluster); |
|
|
|
|
uint32_t clu_addr(const FAT16* fat, const uint16_t cluster); |
|
|
|
|
|
|
|
|
|
/** Find following cluster using FAT for jumps */ |
|
|
|
|
uint16_t next_clu(const FAT16* fat, uint16_t cluster); |
|
|
|
@ -36,8 +36,8 @@ uint16_t alloc_cluster(const FAT16* fat); |
|
|
|
|
/** Zero out entire cluster. */ |
|
|
|
|
void wipe_cluster(const FAT16* fat, const uint16_t clu); |
|
|
|
|
|
|
|
|
|
/** Write new file size (also to the disk). Does not allocate clusters. */ |
|
|
|
|
void set_file_size(FAT16_FILE* file, uint32_t size); |
|
|
|
|
/** Free cluster chain, starting at given number */ |
|
|
|
|
void free_cluster_chain(const FAT16* fat, uint16_t clu); |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if there is already a file of given RAW name |
|
|
|
@ -45,6 +45,12 @@ void set_file_size(FAT16_FILE* file, uint32_t size); |
|
|
|
|
*/ |
|
|
|
|
bool dir_contains_file_raw(FAT16_FILE* dir, char* fname); |
|
|
|
|
|
|
|
|
|
/** Write a value into FAT */ |
|
|
|
|
void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value); |
|
|
|
|
|
|
|
|
|
/** Read a value from FAT */ |
|
|
|
|
uint16_t read_fat(const FAT16* fat, const uint16_t cluster); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// =========== INTERNAL FUNCTION IMPLEMENTATIONS =========
|
|
|
|
|
|
|
|
|
@ -126,8 +132,22 @@ void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value) |
|
|
|
|
{ |
|
|
|
|
fat->dev->seek(fat->fat_addr + (cluster * 2)); |
|
|
|
|
fat->dev->write16(value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t read_fat(const FAT16* fat, const uint16_t cluster) |
|
|
|
|
{ |
|
|
|
|
fat->dev->seek(fat->fat_addr + (cluster * 2)); |
|
|
|
|
return fat->dev->read16(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Get cluster starting address */ |
|
|
|
|
uint32_t clu_start(const FAT16* fat, const uint16_t cluster) |
|
|
|
|
uint32_t clu_addr(const FAT16* fat, const uint16_t cluster) |
|
|
|
|
{ |
|
|
|
|
if (cluster < 2) return fat->rd_addr; |
|
|
|
|
return fat->data_addr + (cluster - 2) * fat->bs.bytes_per_cluster; |
|
|
|
@ -136,8 +156,7 @@ uint32_t clu_start(const FAT16* fat, const uint16_t cluster) |
|
|
|
|
|
|
|
|
|
uint16_t next_clu(const FAT16* fat, uint16_t cluster) |
|
|
|
|
{ |
|
|
|
|
fat->dev->seek(fat->fat_addr + (cluster * 2)); |
|
|
|
|
return fat->dev->read16(); |
|
|
|
|
return read_fat(fat, cluster); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -151,7 +170,7 @@ uint32_t clu_add(const FAT16* fat, uint16_t cluster, uint32_t addr) |
|
|
|
|
addr -= fat->bs.bytes_per_cluster; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return clu_start(fat, cluster) + addr; |
|
|
|
|
return clu_addr(fat, cluster) + addr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -163,7 +182,7 @@ uint32_t clu_add(const FAT16* fat, uint16_t cluster, uint32_t addr) |
|
|
|
|
*/ |
|
|
|
|
void wipe_cluster(const FAT16* fat, const uint16_t clu) |
|
|
|
|
{ |
|
|
|
|
uint32_t addr = clu_start(fat, clu); |
|
|
|
|
uint32_t addr = clu_addr(fat, clu); |
|
|
|
|
|
|
|
|
|
const BLOCKDEV* dev = fat->dev; |
|
|
|
|
|
|
|
|
@ -185,14 +204,11 @@ uint16_t alloc_cluster(const FAT16* fat) |
|
|
|
|
for (i = 2; i < fat->bs.fat_size_sectors * 256; i++) |
|
|
|
|
{ |
|
|
|
|
// read value from FAT
|
|
|
|
|
fat->dev->seek(fat->fat_addr + (i * 2)); |
|
|
|
|
b = fat->dev->read16(); |
|
|
|
|
if (b == 0) |
|
|
|
|
b = read_fat(fat, i); |
|
|
|
|
if (b == 0) // unused cluster
|
|
|
|
|
{ |
|
|
|
|
// Write FFFF to "i", to mark end of file
|
|
|
|
|
b = 0xFFFF; |
|
|
|
|
fat->dev->seek(fat->fat_addr + (i * 2)); |
|
|
|
|
fat->dev->write16(b); |
|
|
|
|
write_fat(fat, i, 0xFFFF); |
|
|
|
|
|
|
|
|
|
// Wipe the cluster
|
|
|
|
|
wipe_cluster(fat, i); |
|
|
|
@ -212,13 +228,30 @@ bool append_cluster(const FAT16* fat, const uint16_t clu) |
|
|
|
|
if (clu2 == 0xFFFF) return false; |
|
|
|
|
|
|
|
|
|
// Write "i" to "clu"
|
|
|
|
|
fat->dev->seek(fat->fat_addr + (clu * 2)); |
|
|
|
|
fat->dev->write16(clu2); |
|
|
|
|
write_fat(fat, clu, clu2); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void free_cluster_chain(const FAT16* fat, uint16_t clu) |
|
|
|
|
{ |
|
|
|
|
do { |
|
|
|
|
// get address of the next cluster
|
|
|
|
|
const uint16_t clu2 = read_fat(fat, clu); |
|
|
|
|
|
|
|
|
|
// mark cluster as unused
|
|
|
|
|
write_fat(fat, clu, 0x0000); |
|
|
|
|
|
|
|
|
|
printf("Cluster free at %d\n", clu); |
|
|
|
|
|
|
|
|
|
// advance
|
|
|
|
|
clu = clu2; |
|
|
|
|
|
|
|
|
|
} while (clu != 0xFFFF); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if there is already a file of given RAW name |
|
|
|
|
* Raw name - name as found on disk, not "display name". |
|
|
|
@ -244,18 +277,6 @@ bool dir_contains_file_raw(FAT16_FILE* dir, char* fname) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Write new file size (also to the disk). Does not allocate clusters. */ |
|
|
|
|
void set_file_size(FAT16_FILE* file, uint32_t size) |
|
|
|
|
{ |
|
|
|
|
// Find address for storing the size
|
|
|
|
|
const uint32_t addr = clu_add(file->fat, file->clu, file->num * 32 + 28); |
|
|
|
|
file->size = size; |
|
|
|
|
|
|
|
|
|
const BLOCKDEV* dev = file->fat->dev; |
|
|
|
|
dev->seek(addr); |
|
|
|
|
dev->store(&size, 4); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// =============== PUBLIC FUNCTION IMPLEMENTATIONS =================
|
|
|
|
|
|
|
|
|
@ -309,7 +330,7 @@ bool fat16_fseek(FAT16_FILE* file, uint32_t addr) |
|
|
|
|
addr -= file->fat->bs.bytes_per_cluster; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
file->cur_abs = clu_start(file->fat, file->cur_clu) + addr; |
|
|
|
|
file->cur_abs = clu_addr(file->fat, file->cur_clu) + addr; |
|
|
|
|
file->cur_ofs = addr; |
|
|
|
|
|
|
|
|
|
// Physically seek to that location
|
|
|
|
@ -331,7 +352,7 @@ void fat16_fopen(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, |
|
|
|
|
uint32_t addr; |
|
|
|
|
if (dir_cluster == 0) |
|
|
|
|
{ |
|
|
|
|
addr = clu_start(fat, dir_cluster) + num * 32; // root directory, max 512 entries.
|
|
|
|
|
addr = clu_addr(fat, dir_cluster) + num * 32; // root directory, max 512 entries.
|
|
|
|
|
} else |
|
|
|
|
{ |
|
|
|
|
addr = clu_add(fat, dir_cluster, num * 32); // cluster + N (wrapping to next cluster if needed)
|
|
|
|
@ -461,7 +482,7 @@ bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len) |
|
|
|
|
if (file->cur_ofs >= fat->bs.bytes_per_cluster) |
|
|
|
|
{ |
|
|
|
|
file->cur_clu = next_clu(fat, file->cur_clu); |
|
|
|
|
file->cur_abs = clu_start(fat, file->cur_clu); |
|
|
|
|
file->cur_abs = clu_addr(fat, file->cur_clu); |
|
|
|
|
file->cur_ofs = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -519,13 +540,13 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len) |
|
|
|
|
|
|
|
|
|
// advance cursors to the next cluster
|
|
|
|
|
file->cur_clu = next_clu(fat, file->cur_clu); |
|
|
|
|
file->cur_abs = clu_start(fat, file->cur_clu); |
|
|
|
|
file->cur_abs = clu_addr(fat, file->cur_clu); |
|
|
|
|
file->cur_ofs = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Save new size
|
|
|
|
|
set_file_size(file, pos_start + len); |
|
|
|
|
fat16_set_file_size(file, pos_start + len); |
|
|
|
|
|
|
|
|
|
// Seek back to where it was before
|
|
|
|
|
fat16_fseek(file, pos_start); |
|
|
|
@ -553,7 +574,7 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len) |
|
|
|
|
if (file->cur_ofs >= fat->bs.bytes_per_cluster) |
|
|
|
|
{ |
|
|
|
|
file->cur_clu = next_clu(fat, file->cur_clu); |
|
|
|
|
file->cur_abs = clu_start(fat, file->cur_clu); |
|
|
|
|
file->cur_abs = clu_addr(fat, file->cur_clu); |
|
|
|
|
file->cur_ofs = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -880,7 +901,47 @@ char* fat16_undisplay_name(const char* name, char* fixed) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Write new file size (also to the disk). Does not allocate clusters. */ |
|
|
|
|
void fat16_set_file_size(FAT16_FILE* file, uint32_t size) |
|
|
|
|
{ |
|
|
|
|
const FAT16* fat = file->fat; |
|
|
|
|
const BLOCKDEV* dev = file->fat->dev; |
|
|
|
|
|
|
|
|
|
// Find address for storing the size
|
|
|
|
|
const uint32_t addr = clu_add(fat, file->clu, file->num * 32 + 28); |
|
|
|
|
file->size = size; |
|
|
|
|
|
|
|
|
|
dev->seek(addr); |
|
|
|
|
dev->store(&size, 4); |
|
|
|
|
|
|
|
|
|
// Seek to the end of the file, to make sure clusters are allocated
|
|
|
|
|
fat16_fseek(file, size - 1); |
|
|
|
|
|
|
|
|
|
const uint16_t next = next_clu(fat, file->cur_clu); |
|
|
|
|
if (next != 0xFFFF) |
|
|
|
|
{ |
|
|
|
|
printf("Trimming file clusters\n"); |
|
|
|
|
|
|
|
|
|
free_cluster_chain(fat, next); |
|
|
|
|
|
|
|
|
|
// Mark that there's no further clusters
|
|
|
|
|
write_fat(fat, file->cur_clu, 0xFFFF); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void fat16_delete_file(FAT16_FILE* file) |
|
|
|
|
{ |
|
|
|
|
const FAT16* fat = file->fat; |
|
|
|
|
|
|
|
|
|
// seek to file record
|
|
|
|
|
fat->dev->seek(clu_add(fat, file->clu, file->num * 32)); |
|
|
|
|
|
|
|
|
|
// mark as deleted
|
|
|
|
|
fat->dev->write(0xE5); // "deleted" mark
|
|
|
|
|
|
|
|
|
|
// free allocated clusters
|
|
|
|
|
free_cluster_chain(fat, file->clu_start); |
|
|
|
|
|
|
|
|
|
file->type = FT_DELETED; |
|
|
|
|
} |
|
|
|
|