diff --git a/.gitignore b/.gitignore index 3f1ff6e..e11677c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,8 @@ # Debug files *.dSYM/ +./test + # Code::Blocks garbage *.depend *.layout diff --git a/fat16.c b/fat16.c index c4fce6e..757f0bb 100644 --- a/fat16.c +++ b/fat16.c @@ -51,6 +51,9 @@ 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); +/** Go through a directory, and open first NONE or DELETED file. */ +bool find_empty_file_slot(FAT16_FILE* file); + // =========== INTERNAL FUNCTION IMPLEMENTATIONS ========= @@ -310,7 +313,8 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c file->type = FT_FILE; - switch (file->name[0]) + const uint8_t c = file->name[0]; + switch (c) { case 0x00: file->type = FT_NONE; @@ -339,7 +343,14 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c break; default: - file->type = FT_FILE; + if (c < 32) + { + file->type = FT_INVALID; // File is corrupt, treat it as invalid + } + else + { + file->type = FT_FILE; + } } // handle subdir, label @@ -353,7 +364,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c } else if (file->attribs == 0x0F) { - file->type = FT_LFN; // long name special file, can be safely ignored + file->type = FT_LFN; // long name special file, can be ignored } // add a FAT pointer @@ -364,6 +375,105 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c } +void delete_file_do(FAT16_FILE* file) +{ + const FAT16* fat = file->fat; + + // seek to file record + fat->dev->seek(clu_offs(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; +} + + + +/** + * Write information into a file header. + * "file" is an open handle. + */ +void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start) +{ + const BLOCKDEV* dev = file->fat->dev; + + const uint32_t entrystart = clu_offs(file->fat, file->clu, file->num * 32); + + // store the file name + dev->seek(entrystart); + dev->store(fname_raw, 11); + + // attributes + dev->write(attribs); + + // 10 reserved, 2+2 date & time + // (could just skip, but better to fill with zeros) + for (uint8_t i = 0; i < 14; i++) + { + dev->write(0); + } + + // addr of the first file cluster + dev->write16(clu_start); + + // file size (uint32_t) + dev->write16(0); + dev->write16(0); + + // reopen file - load & parse the information just written + open_file(file->fat, file, file->clu, file->num); +} + + +/** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */ +bool find_empty_file_slot(FAT16_FILE* file) +{ + const uint16_t clu = file->clu; + const FAT16* fat = file->fat; + + // Find free directory entry that can be used + for (uint16_t num = 0; num < 0xFFFF; num++) + { + // root directory has fewer entries, error if trying + // to add one more. + if (file->clu == 0 && num >= fat->bs.root_entries) + return false; + + // Resolve addres of next file entry + uint32_t addr; + do + { + addr = clu_offs(fat, file->clu, num * 32); + + if (addr == 0xFFFF) + { + // end of chain of allocated clusters for the directory + // append new cluster, return false on failure + if (!append_cluster(fat, file->clu)) return false; + } + + // if new cluster was just added, repeat. + } + while (addr == 0xFFFF); + + // Open the file entry + open_file(fat, file, clu, num); + + // Check if can be overwritten + if (file->type == FT_DELETED || file->type == FT_NONE) + { + return true; + } + } + + return false; // not found. +} + + // =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= /** Initialize a FAT16 handle */ @@ -661,86 +771,6 @@ bool fat16_find(FAT16_FILE* dir, const char* name) return dir_contains_file_raw(dir, fname); } - -/** Go through a directory, and open first NONE or DELETED file. */ -bool find_empty_file_slot(FAT16_FILE* file) -{ - const uint16_t clu = file->clu; - const FAT16* fat = file->fat; - - // Find free directory entry that can be used - for (uint16_t num = 0; num < 0xFFFF; num++) - { - // root directory has fewer entries, error if trying - // to add one more. - if (file->clu == 0 && num >= fat->bs.root_entries) - return false; - - // Resolve addres of next file entry - uint32_t addr; - do - { - addr = clu_offs(fat, file->clu, num * 32); - - if (addr == 0xFFFF) - { - // end of chain of allocated clusters for the directory - // append new cluster, return false on failure - if (!append_cluster(fat, file->clu)) return false; - } - - // if new cluster was just added, repeat. - } - while (addr == 0xFFFF); - - // Open the file entry - open_file(fat, file, clu, num); - - // Check if can be overwritten - if (file->type == FT_DELETED || file->type == FT_NONE) - { - return true; - } - } - - return false; // not found. -} - - -/** Write information into a file header (alloc first cluster). "file" is an open handle. */ -void write_file_header(FAT16_FILE* file, const char* fname, const uint8_t attribs, const uint16_t newclu) -{ - const FAT16* fat = file->fat; - const BLOCKDEV* dev = fat->dev; - - const uint32_t entrystart = clu_offs(fat, file->clu, file->num * 32); - - // store the file name - dev->seek(entrystart); - dev->store(fname, 11); - - // attributes - dev->write(attribs); - - // 10 reserved, 2+2 date & time - // (could just skip, but better to fill with zeros) - for (uint8_t i = 0; i < 14; i++) - { - dev->write(0); - } - - // addr of the first file cluster - dev->write16(newclu); - - // file size (uint32_t) - dev->write16(0); - dev->write16(0); - - // reopen file - load & parse the information just written - open_file(fat, file, file->clu, file->num); -} - - bool fat16_mkfile(FAT16_FILE* file, const char* name) { // Convert filename to zero padded raw string @@ -986,19 +1016,83 @@ void fat16_resize(FAT16_FILE* file, uint32_t size) } } +/** Delete a simple file */ +bool fat16_rmfile(FAT16_FILE* file) +{ + if (file->type != FT_FILE) + return false; // not a simple file -void fat16_delete(FAT16_FILE* file) + delete_file_do(file); + return true; +} + + +/** Delete an empty directory */ +bool fat16_rmdir(FAT16_FILE* file) { + if (file->type != FT_SUBDIR) + return false; // not a subdirectory entry + const FAT16* fat = file->fat; - // seek to file record - fat->dev->seek(clu_offs(fat, file->clu, file->num * 32)); + const uint16_t dir_clu = file->clu; + const uint16_t dir_num = file->num; - // mark as deleted - fat->dev->write(0xE5); // "deleted" mark + // Look for valid files and subdirs in the directory + if (!fat16_opendir(file)) + return false; // could not open - // free allocated clusters - free_cluster_chain(fat, file->clu_start); + uint8_t cnt = 0; + do + { + // Stop on apparent corrupt structure (missing "." or "..") + // Can safely delete the folder. + if (cnt == 0 && file->type != FT_SELF) break; + if (cnt == 1 && file->type != FT_PARENT) break; - file->type = FT_DELETED; + // Found valid file + if (file->type == FT_SUBDIR || file->type == FT_FILE) + { + // Valid child file was found, aborting. + // reopen original file + open_file(fat, file, dir_clu, dir_num); + return false; + } + + if (cnt < 2) cnt++; + } + while (fat16_next(file)); + + // reopen original file + open_file(fat, file, dir_clu, dir_num); + + // and delete as ordinary file + delete_file_do(file); + + return true; +} + + +bool fat16_parent(FAT16_FILE* file) +{ + const uint16_t clu = file->clu; + const uint16_t num = file->num; + + // open second entry of the directory + open_file(file->fat, file, file->clu, 1); + + // if it's a valid PARENT link, follow it. + if (file->type == FT_PARENT) + { + open_file(file->fat, file, file->clu_start, 0); + return true; + } + else + { + // maybe in root already? + + // reopen original file + open_file(file->fat, file, clu, num); + return false; + } } diff --git a/fat16.h b/fat16.h index 4460878..e11dbee 100644 --- a/fat16.h +++ b/fat16.h @@ -33,6 +33,7 @@ typedef enum FT_PARENT = 'P', FT_LABEL = 'L', FT_LFN = '~', + FT_INVALID = 'i', // not recognized weird file FT_SELF = '.', FT_FILE = 'F' } FAT16_FT; @@ -194,8 +195,18 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name); void fat16_resize(FAT16_FILE* file, uint32_t size); -/** Delete a file entry and free clusters. Does NOT descend into subdirectories. */ -void fat16_delete(FAT16_FILE* file); +/** + * Delete a file entry and free clusters. + * Does NOT work on folders. + */ +bool fat16_rmfile(FAT16_FILE* file); + + +/** + * Delete an empty directory. + * Calling with non-subfolder entry or non-empty directory will cause error. + */ +bool fat16_rmdir(FAT16_FILE* file); // --------- NAVIGATION ------------ @@ -214,6 +225,11 @@ bool fat16_next(FAT16_FILE* file); */ bool fat16_opendir(FAT16_FILE* file); +/** + * Open a parent directory. Fails in root. + */ +bool fat16_parent(FAT16_FILE* file); + /** Rewind to first file in directory */ void fat16_first(FAT16_FILE* file); diff --git a/main.c b/main.c index 37c4434..58afa67 100644 --- a/main.c +++ b/main.c @@ -118,31 +118,46 @@ int main() fat16_root(&fat, &file); - if (fat16_find(&file, "FOLDER")) - { - if (fat16_opendir(&file)) - { - printf("Listing FOLDER:\n"); - - do - { - printf("File name: %s, %c, %d B, @ 0x%x\n", - fat16_dispname(&file, str), - file.type, file.size, file.clu_start); - } - while (fat16_next(&file)); - - if (fat16_find(&file, "banana.exe")) - { - char m[49]; - fat16_fread(&file, m, 49); - printf("%.49s\n", m); - } - } - } +// if (fat16_find(&file, "FOLDER")) +// { +// if (fat16_opendir(&file)) +// { +// printf("Listing FOLDER:\n"); + +// do +// { +// printf("File name: %s, %c, %d B, @ 0x%x\n", +// fat16_dispname(&file, str), +// file.type, file.size, file.clu_start); +// } +// while (fat16_next(&file)); + +// char m[49]; + +// if (fat16_find(&file, "banana.exe")) +// { +// fat16_fread(&file, m, 49); +// printf("%.49s\n", m); +// } + +// fat16_rmfile(&file); + +// if (fat16_parent(&file)) { +// printf("Current file: %s\n", fat16_dispname(&file, m)); +// } + +// printf("Found? %d\n", fat16_find(&file, "FOLDER2")); +// printf("Deleted? %d\n", fat16_rmdir(&file)); +// } +// } - //fat16_mkfile(&file, "banana.exe"); - //fat16_fwrite(&file, "THIS IS A STRING STORED IN A FILE CALLED BANANA!\n", 49); +// printf("Found? %d\n", fat16_find(&file, "FOLDER2")); +// printf("Deleted? %d\n", fat16_rmdir(&file)); + +// if (fat16_mkfile(&file, "banana2.exe")) +// { +// fat16_fwrite(&file, "THIS IS A STRING STORED IN A FILE CALLED BANANA!\n", 49); +// } // fat16_find(&file, "banana.exe"); // char m[49]; diff --git a/test b/test deleted file mode 100755 index 3e2a246..0000000 Binary files a/test and /dev/null differ