diff --git a/fat16.c b/fat16.c index fcb922d..01c3a7d 100644 --- a/fat16.c +++ b/fat16.c @@ -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; +} diff --git a/fat16.h b/fat16.h index 2c6f340..9fc1f11 100644 --- a/fat16.h +++ b/fat16.h @@ -17,7 +17,7 @@ typedef struct { // Absolute seek void (*seek)(const uint32_t); // Relative seek - void (*rseek)(const uint16_t); + void (*rseek)(const int16_t); } BLOCKDEV; @@ -169,7 +169,14 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len); */ bool fat16_newfile(FAT16_FILE* directory, FAT16_FILE* file, const char* name); +/** + * Write new file size (also to the disk). + * Allocates / frees needed clusters, does not erase them. + */ +void fat16_set_file_size(FAT16_FILE* file, uint32_t size); +/** Delete a file entry and free clusters. Does NOT descend into subdirectories. */ +void fat16_delete_file(FAT16_FILE* file); // --------- NAVIGATION ------------ diff --git a/main.c b/main.c index 02f0dda..22a62b2 100644 --- a/main.c +++ b/main.c @@ -18,7 +18,7 @@ void test_seek(const uint32_t pos) fseek(testf, pos, SEEK_SET); } -void test_rseek(const uint16_t pos) +void test_rseek(const int16_t pos) { fseek(testf, pos, SEEK_CUR); } @@ -112,22 +112,43 @@ int main(int argc, char const *argv[]) do { if (!fat16_is_file_valid(&file)) continue; - printf("File name: %s, %c, %d B\n", + printf("File name: %s, %c, %d B, @ 0x%x\n", fat16_display_name(&file, str), - file.type, file.size); + file.type, file.size, file.clu_start); } while (fat16_next(&file)); fat16_open_root(&fat, &file); - printf("Exists? %d\n", fat16_find_file(&file, "nuclear.war")); - printf("Size: %d\n", file.size); +// bool found = fat16_find_file(&file, "NEW_FILE.DAT"); +// +// if (found) +// { +// fat16_delete_file(&file); +// fat16_set_file_size(&file, 16000); +// } + + //printf("Exists? %d\n", fat16_find_file(&file, "nuclear.war")); + //printf("Size: %d\n", file.size); + + //fat16_set_file_size(&file, 5); //fat16_fseek(&file, 40000); //fat16_fwrite(&file, "BANANA", 6); - //FAT16_FILE neu; - //fat16_newfile(&file, &neu, "NEWFILE.MP3"); +// FAT16_FILE neu; +// bool ok = fat16_newfile(&file, &neu, "NEWFILE3.DAT"); +// if (!ok) { +// printf("FAIL."); +// return -1; +// } +// +// char c = '_'; +// for (uint16_t i = 0; i < 35000; i++) { +// fat16_fwrite(&neu, &i, 2); +// fat16_fwrite(&neu, &c, 1); +// } + //fat16_fwrite(&neu, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 16); @@ -147,6 +168,15 @@ int main(int argc, char const *argv[]) // // printf("%.5s\n", boo); + +// char ham[20000]; +// +// fat16_find_file(&file, "HAMLET.TXT"); +// fat16_fread(&file, ham, 20000); +// ham[19999] = 0; +// printf("%s\n", ham); + + test_close(); return 0;