diff --git a/fat16.c b/fat16.c index b3f0b69..f2a71e5 100644 --- a/fat16.c +++ b/fat16.c @@ -706,13 +706,13 @@ void fat16_first(FAT16_FILE* file) /** Open a directory denoted by the file. */ -bool fat16_opendir(FAT16_FILE* file) +bool fat16_opendir(FAT16_FILE* dir) { // Don't open non-dirs and "." directory. - if (!(file->attribs & FA_DIR) || file->type == FT_SELF) + if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF) return false; - open_file(file->fat, file, file->clu_start, 0); + open_file(dir->fat, dir, dir->clu_start, 0); return true; } diff --git a/fat16.h b/fat16.h index 40809a4..7db054d 100644 --- a/fat16.h +++ b/fat16.h @@ -1,6 +1,10 @@ #pragma once -/** Abstract block device interface */ +/** + * Abstract block device interface + * + * Populate this with pointers to your I/O functions. + */ typedef struct { // Sequential read @@ -20,7 +24,10 @@ typedef struct // ------------------------------- -/** file types (values don't matter) */ +/** + * File types (values can be used for debug printing). + * Accessible using file->type + */ typedef enum { FT_NONE = '-', @@ -29,102 +36,73 @@ typedef enum FT_PARENT = 'P', FT_LABEL = 'L', FT_LFN = '~', - FT_INVALID = 'i', // not recognized weird file + FT_INVALID = '?', // not recognized weird file FT_SELF = '.', FT_FILE = 'F' } FAT16_FT; -// File Attributes (bit flags) -#define FA_READONLY 0x01 // read only file -#define FA_HIDDEN 0x02 // hidden file -#define FA_SYSTEM 0x04 // system file -#define FA_LABEL 0x08 // volume label entry, found only in root directory. -#define FA_DIR 0x10 // subdirectory -#define FA_ARCHIVE 0x20 // archive flag - - -/** Boot Sector structure - INTERNAL! */ -typedef struct __attribute__((packed)) -{ - - // Fields loaded directly from disk: - - // 13 bytes skipped - uint8_t sectors_per_cluster; - uint16_t reserved_sectors; - uint8_t num_fats; - uint16_t root_entries; - // 3 bytes skipped - uint16_t fat_size_sectors; - // 8 bytes skipped - uint32_t total_sectors; // if "short size sectors" is used, it's copied here too - // 7 bytes skipped - char volume_label[11]; // space padded, no terminator - - // Added fields: +// Include definitions of fully internal structs +#include "fat16_internal.h" - uint32_t bytes_per_cluster; -} -Fat16BootSector; - - -/** FAT filesystem handle - private fields! */ +/** + * File handle struct. + * + * File handle contains cursor, file name, type, size etc. + * Everything (files, dirs) is accessed using this. + */ typedef struct __attribute__((packed)) { - // Backing block device - const BLOCKDEV* dev; - - // Root directory sector start - uint32_t rd_addr; - - // Start of first cluster (number "2") - uint32_t data_addr; + /** + * Raw file name. Starting 0x05 was converted to 0xE5. + * To get PRINTABLE file name, use fat16_dispname() + */ + uint8_t name[11]; - // Start of fat table - uint32_t fat_addr; - - // Boot sector data struct - Fat16BootSector bs; -} -FAT16; + /** + * File attributes - bit field composed of FA_* flags + * (internal) + */ + uint8_t attribs; + // 14 bytes skipped (10 reserved, date, time) -/** File handle struct */ -typedef struct __attribute__((packed)) -{ - // Fields loaded directly from disk: - - uint8_t name[11]; // Starting 0x05 converted to 0xE5, other "magic chars" left intact - uint8_t attribs; // composed of FA_* constants - // 14 bytes skipped + /** First cluster of the file. (internal) */ uint16_t clu_start; + + /** + * File size in bytes. + * This is the current allocated and readable file size. + */ uint32_t size; - // Added fields: + // --- the following fields are added when reading --- + + /** File type. */ FAT16_FT type; - // --- Private fields --- - // Cursor + // --- INTERNAL FIELDS --- + + // Cursor variables. (internal) uint32_t cur_abs; // absolute position in device uint32_t cur_rel; // relative position in file uint16_t cur_clu; // cluster where the cursor is uint16_t cur_ofs; // offset within the active cluster - // File position in the directory + // File position in the directory. (internal) uint16_t clu; // first cluster of directory - uint16_t num; // fiel entry number + uint16_t num; // file entry number - // pointer to FAT + // Pointer to the FAT16 handle. (internal) const FAT16* fat; } FAT16_FILE; -/** Initialize a filesystem */ +/** Initialize the file system - store into "fat" */ void fat16_init(const BLOCKDEV* dev, FAT16* fat); @@ -132,14 +110,13 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat); * Open the first file of the root directory. * The file may be invalid (eg. a volume label, deleted etc), * or blank (type FT_NONE) if the filesystem is empty. - * - * Either way, the prev and next functions will work as expected. */ void fat16_root(const FAT16* fat, FAT16_FILE* file); /** * Resolve the disk label. + * That can be in the Boot Sector, or in the first root directory entry. */ char* fat16_disk_label(const FAT16* fat, char* label_out); @@ -185,29 +162,29 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name); /** - * Write new file size (also to the disk). - * Allocates / frees needed clusters, does not erase them. + * Set new file size. + * Allocates / frees needed clusters, does NOT erase them. + * + * Useful mainly for shrinking. */ void fat16_resize(FAT16_FILE* file, uint32_t size); /** - * Delete a file entry and free clusters. - * Does NOT work on folders. + * Delete a *FILE* and free it's clusters. */ bool fat16_rmfile(FAT16_FILE* file); /** - * Delete an empty directory. - * Calling with non-subfolder entry or non-empty directory will cause error. + * Delete an empty *DIRECTORY* and free it's clusters. */ bool fat16_rmdir(FAT16_FILE* file); /** - * Delete a file or directory, regardless of type. - * Directories are deleted recursively. + * Delete a file or directory, even FT_LFN and FT_INVALID. + * Directories are deleted recursively (!) */ bool fat16_delete(FAT16_FILE* file); @@ -226,17 +203,19 @@ bool fat16_next(FAT16_FILE* file); /** * Open a subdirectory denoted by the file. - * Provided handle changes to first entry of the directory. + * Provided handle changes to the first entry of the directory. */ -bool fat16_opendir(FAT16_FILE* file); +bool fat16_opendir(FAT16_FILE* dir); + /** * Open a parent directory. Fails in root. + * Provided handle changes to the first entry of the parent directory. */ bool fat16_parent(FAT16_FILE* file); -/** Rewind to first file in directory */ +/** Jump to first file in this directory */ void fat16_first(FAT16_FILE* file); diff --git a/fat16_internal.h b/fat16_internal.h new file mode 100644 index 0000000..d723ef5 --- /dev/null +++ b/fat16_internal.h @@ -0,0 +1,62 @@ +#pragma once + +// Internal types and stuff that is needed in the header for declarations, +// but is not a part of the public API. + +/** Boot Sector structure */ +typedef struct __attribute__((packed)) +{ + + // Fields loaded directly from disk: + + // 13 bytes skipped + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t num_fats; + uint16_t root_entries; + // 3 bytes skipped + uint16_t fat_size_sectors; + // 8 bytes skipped + uint32_t total_sectors; // if "short size sectors" is used, it's copied here too + // 7 bytes skipped + char volume_label[11]; // space padded, no terminator + + // Added fields: + + uint32_t bytes_per_cluster; + +} +Fat16BootSector; + + +/** FAT filesystem handle */ +typedef struct __attribute__((packed)) +{ + // Backing block device + const BLOCKDEV* dev; + + // Root directory sector start + uint32_t rd_addr; + + // Start of first cluster (number "2") + uint32_t data_addr; + + // Start of fat table + uint32_t fat_addr; + + // Boot sector data struct + Fat16BootSector bs; +} +FAT16; + + +/** + * File Attributes (bit flags) + * Accessible using file->attribs + */ +#define FA_READONLY 0x01 // read only file +#define FA_HIDDEN 0x02 // hidden file +#define FA_SYSTEM 0x04 // system file +#define FA_LABEL 0x08 // volume label entry, found only in root directory. +#define FA_DIR 0x10 // subdirectory +#define FA_ARCHIVE 0x20 // archive flag