Added great improvements from avr-lib, including huge name changes.

master
Ondřej Hruška 10 years ago
parent adae8b8cdf
commit 50b933231c
  1. 66
      blockdev.h
  2. 209
      fat16.c
  3. 117
      fat16.h
  4. 1
      fat16_internal.h
  5. 14
      main.c

@ -0,0 +1,66 @@
#pragma once
//
// Block device interface, somewhat akin to stream.h
// Used for filesystem implementations.
//
#include <stdint.h>
/** Abstract block device interface
*
* Populate an instance of this with pointers to your I/O functions.
*/
typedef struct
{
/** Sequential read at cursor
* @param dest destination memory structure
* @param len number of bytes to load and store in {dest}
*/
void (*load)(void* dest, const uint16_t len);
/** Sequential write at cursor
* @param src source memory structure
* @param len number of bytes to write
*/
void (*store)(const void* src, const uint16_t len);
/** Write one byte at cursor
* @param b byte to write
*/
void (*write)(const uint8_t b);
/** Read one byte at cursor
* @return the read byte
*/
uint8_t (*read)(void);
/** Absolute seek - set cursor
* @param addr new cursor address
*/
void (*seek)(const uint32_t addr);
/** Relative seek - move cursor
* @param offset cursor address change
*/
void (*rseek)(const int16_t offset);
/** Flush the data buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*
* Tmplementations that do not need this should provide
* a no-op function.
*/
void (*flush)(void);
} BLOCKDEV;

@ -24,7 +24,7 @@ uint16_t next_clu(const FAT16* fat, uint16_t cluster);
uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr); uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr);
/** Read a file entry from directory (dir starting cluster, entry number) */ /** Read a file entry from directory (dir starting cluster, entry number) */
void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num); void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num);
/** Allocate and chain new cluster to a chain starting at given cluster */ /** Allocate and chain new cluster to a chain starting at given cluster */
bool append_cluster(const FAT16* fat, const uint16_t clu); bool append_cluster(const FAT16* fat, const uint16_t clu);
@ -42,7 +42,7 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu);
* Check if there is already a file of given RAW name * Check if there is already a file of given RAW name
* Raw name - name as found on disk, not "display name". * Raw name - name as found on disk, not "display name".
*/ */
bool dir_find_file_raw(FAT16_FILE* dir, const char* fname); bool dir_find_file_raw(FFILE* dir, const char* fname);
/** Write a value into FAT */ /** Write a value into FAT */
void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value); void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value);
@ -103,7 +103,10 @@ uint32_t find_bs(const BLOCKDEV* dev)
// Verify that the boot sector has a valid signature mark // Verify that the boot sector has a valid signature mark
dev->seek(tmp + 510); dev->seek(tmp + 510);
dev->load(&tmp2, 2); dev->load(&tmp2, 2);
if (tmp2 != 0xAA55) continue; // continue to next entry if (tmp2 != 0xAA55)
{
continue; // continue to next entry
}
// return absolute MBR address // return absolute MBR address
return tmp; return tmp;
@ -273,10 +276,10 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu)
* Check if there is already a file of given RAW name * Check if there is already a file of given RAW name
* Raw name - name as found on disk, not "display name". * Raw name - name as found on disk, not "display name".
*/ */
bool dir_find_file_raw(FAT16_FILE* dir, const char* fname) bool dir_find_file_raw(FFILE* dir, const char* fname)
{ {
// rewind // rewind
fat16_first(dir); ff_first(dir);
do do
{ {
@ -296,7 +299,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
return true; // file is already open. return true; // file is already open.
} }
} }
while (fat16_next(dir)); while (ff_next(dir));
return false; return false;
} }
@ -308,7 +311,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
* dir_cluster ... directory start cluster * dir_cluster ... directory start cluster
* num ... entry number in the directory * num ... entry number in the directory
*/ */
void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num) void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num)
{ {
// Resolve starting address // Resolve starting address
uint32_t addr; uint32_t addr;
@ -394,7 +397,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
} }
// Init cursors // Init cursors
fat16_seek(file, 0); ff_seek(file, 0);
} }
@ -403,7 +406,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
* Write information into a file header. * Write information into a file header.
* "file" is an open handle. * "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) void write_file_header(FFILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start)
{ {
const BLOCKDEV* dev = file->fat->dev; const BLOCKDEV* dev = file->fat->dev;
@ -439,9 +442,12 @@ void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t at
// =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= // =============== PUBLIC FUNCTION IMPLEMENTATIONS =================
/** Initialize a FAT16 handle */ /** Initialize a FAT16 handle */
void fat16_init(const BLOCKDEV* dev, FAT16* fat) bool ff_init(const BLOCKDEV* dev, FAT16* fat)
{ {
const uint32_t bs_a = find_bs(dev); const uint32_t bs_a = find_bs(dev);
if (bs_a == 0) return false;
fat->dev = dev; fat->dev = dev;
read_bs(dev, &(fat->bs), bs_a); read_bs(dev, &(fat->bs), bs_a);
fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512); fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512);
@ -449,6 +455,8 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat)
fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long
fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512); fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512);
return true;
} }
@ -456,7 +464,7 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat)
* Move file cursor to a position relative to file start * Move file cursor to a position relative to file start
* Allows seek past end of file, will allocate new cluster if needed. * Allows seek past end of file, will allocate new cluster if needed.
*/ */
bool fat16_seek(FAT16_FILE* file, uint32_t addr) bool ff_seek(FFILE* file, uint32_t addr)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
@ -504,7 +512,7 @@ bool fat16_seek(FAT16_FILE* file, uint32_t addr)
* Check if file is a regular file or directory entry. * Check if file is a regular file or directory entry.
* Those files can be shown to user. * Those files can be shown to user.
*/ */
bool fat16_is_regular(const FAT16_FILE* file) bool ff_is_regular(const FFILE* file)
{ {
switch (file->type) switch (file->type)
{ {
@ -522,13 +530,19 @@ bool fat16_is_regular(const FAT16_FILE* file)
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
bool fat16_read(FAT16_FILE* file, void* target, uint32_t len) uint16_t ff_read(FFILE* file, void* target, uint16_t len)
{ {
if (file->cur_abs == 0xFFFF) if (file->cur_abs == 0xFFFF)
return false; // file at the end already return 0; // file at the end already
if (file->cur_rel + len > file->size) if (file->cur_rel + len > file->size)
return false; // Attempt to read more than what is available {
if (file->cur_rel > file->size) return 0;
len = file->size - file->cur_rel;
//return false; // Attempt to read more than what is available
}
const uint16_t len_orig = len;
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
@ -562,18 +576,27 @@ bool fat16_read(FAT16_FILE* file, void* target, uint32_t len)
len -= chunk; len -= chunk;
} }
return true; return len_orig;
} }
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len) bool ff_write_str(FFILE* file, const char* source)
{
uint16_t len = 0;
for (; source[len] != 0; len++);
return ff_write(file, source, len);
}
bool ff_write(FFILE* file, const void* source, uint32_t len)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
if (file->cur_abs == 0xFFFF) if (file->cur_abs == 0xFFFF)
return false; // file at the end already return false; // file past it's end (rare)
// Attempt to write past end of file // Attempt to write past end of file
if (file->cur_rel + len >= file->size) if (file->cur_rel + len >= file->size)
@ -582,14 +605,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
// Seek to the last position // Seek to the last position
// -> fseek will allocate clusters // -> fseek will allocate clusters
if (!fat16_seek(file, pos_start + len)) if (!ff_seek(file, pos_start + len))
return false; // error in seek return false; // error in seek
// Write starts beyond EOF - creating a zero-filled "hole" // Write starts beyond EOF - creating a zero-filled "hole"
if (file->cur_rel > file->size) if (pos_start > file->size + 1)
{ {
// Seek to the end of valid data // Seek to the end of valid data
fat16_seek(file, file->size); ff_seek(file, file->size);
// fill space between EOF and start-of-write with zeros // fill space between EOF and start-of-write with zeros
uint32_t fill = pos_start - file->size; uint32_t fill = pos_start - file->size;
@ -617,22 +640,34 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
} }
} }
// Save new size // Store new size
fat16_resize(file, pos_start + len); file->size = pos_start + len;
// Seek back to where it was before // Seek back to where it was before
fat16_seek(file, pos_start); ff_seek(file, pos_start);
} // (end zerofill) } // (end zerofill)
// write the data // write the data
while (len > 0) while (len > 0)
{
dev->seek(file->cur_abs);
uint16_t chunk;
if (len == 1)
{
dev->write(*((uint8_t*)source));
file->cur_abs++;
file->cur_rel++;
file->cur_ofs++;
chunk = 1;
}
else
{ {
// How much can be stored in this cluster // How much can be stored in this cluster
const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len); chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len);
// store the chunk
dev->seek(file->cur_abs);
dev->store(source, chunk); dev->store(source, chunk);
// advance cursors // advance cursors
@ -642,6 +677,7 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
// Pointer arith! // Pointer arith!
source += chunk; // advance the source pointer source += chunk; // advance the source pointer
}
// detect cluster overflow // detect cluster overflow
if (file->cur_ofs >= fat->bs.bytes_per_cluster) if (file->cur_ofs >= fat->bs.bytes_per_cluster)
@ -662,7 +698,7 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
/** Open next file in the directory */ /** Open next file in the directory */
bool fat16_next(FAT16_FILE* file) bool ff_next(FFILE* file)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
@ -686,7 +722,7 @@ bool fat16_next(FAT16_FILE* file)
/** Open previous file in the directory */ /** Open previous file in the directory */
bool fat16_prev(FAT16_FILE* file) bool ff_prev(FFILE* file)
{ {
if (file->num == 0) if (file->num == 0)
return false; // first file already return false; // first file already
@ -698,14 +734,14 @@ bool fat16_prev(FAT16_FILE* file)
/** Rewind to first file in directory */ /** Rewind to first file in directory */
void fat16_first(FAT16_FILE* file) void ff_first(FFILE* file)
{ {
open_file(file->fat, file, file->clu, 0); open_file(file->fat, file, file->clu, 0);
} }
/** Open a directory denoted by the file. */ /** Open a directory denoted by the file. */
bool fat16_opendir(FAT16_FILE* dir) bool ff_opendir(FFILE* dir)
{ {
// Don't open non-dirs and "." directory. // Don't open non-dirs and "." directory.
if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF) if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF)
@ -716,7 +752,7 @@ bool fat16_opendir(FAT16_FILE* dir)
} }
void fat16_root(const FAT16* fat, FAT16_FILE* file) void ff_root(const FAT16* fat, FFILE* file)
{ {
open_file(fat, file, 0, 0); open_file(fat, file, 0, 0);
} }
@ -727,16 +763,16 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file)
* If file is found, "dir" will contain it's handle. * If file is found, "dir" will contain it's handle.
* Either way, "dir" gets modified and you may need to rewind it afterwards. * Either way, "dir" gets modified and you may need to rewind it afterwards.
*/ */
bool fat16_find(FAT16_FILE* dir, const char* name) bool ff_open(FFILE* dir, const char* name)
{ {
char fname[11]; char fname[11];
fat16_rawname(name, fname); ff_rawname(name, fname);
return dir_find_file_raw(dir, fname); return dir_find_file_raw(dir, fname);
} }
/** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */ /** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */
bool find_empty_file_slot(FAT16_FILE* file) bool find_empty_file_slot(FFILE* file)
{ {
const uint16_t clu = file->clu; const uint16_t clu = file->clu;
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
@ -781,15 +817,15 @@ bool find_empty_file_slot(FAT16_FILE* file)
bool fat16_mkfile(FAT16_FILE* file, const char* name) bool ff_newfile(FFILE* file, const char* name)
{ {
// Convert filename to zero padded raw string // Convert filename to zero padded raw string
char fname[11]; char fname[11];
fat16_rawname(name, fname); ff_rawname(name, fname);
// Abort if file already exists // Abort if file already exists
bool exists = dir_find_file_raw(file, fname); bool exists = dir_find_file_raw(file, fname);
fat16_first(file); // rewind dir ff_first(file); // rewind dir
if (exists) if (exists)
return false; // file already exists in the dir. return false; // file already exists in the dir.
@ -809,15 +845,15 @@ bool fat16_mkfile(FAT16_FILE* file, const char* name)
* Create a sub-directory of given name. * Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".." * Directory is allocated and populated with entries "." and ".."
*/ */
bool fat16_mkdir(FAT16_FILE* file, const char* name) bool ff_mkdir(FFILE* file, const char* name)
{ {
// Convert filename to zero padded raw string // Convert filename to zero padded raw string
char fname[11]; char fname[11];
fat16_rawname(name, fname); ff_rawname(name, fname);
// Abort if file already exists // Abort if file already exists
bool exists = dir_find_file_raw(file, fname); bool exists = dir_find_file_raw(file, fname);
fat16_first(file); // rewind dir ff_first(file); // rewind dir
if (exists) if (exists)
return false; // file already exusts in the dir. return false; // file already exusts in the dir.
@ -840,20 +876,20 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name)
write_file_header(file, ".. ", FA_DIR, parent_clu); write_file_header(file, ".. ", FA_DIR, parent_clu);
// rewind. // rewind.
fat16_first(file); ff_first(file);
return true; return true;
} }
char* fat16_disk_label(const FAT16* fat, char* label_out) char* ff_disk_label(const FAT16* fat, char* label_out)
{ {
FAT16_FILE first; FFILE first;
fat16_root(fat, &first); ff_root(fat, &first);
if (first.type == FT_LABEL) if (first.type == FT_LABEL)
{ {
return fat16_dispname(&first, label_out); return ff_dispname(&first, label_out);
} }
// find where spaces end // find where spaces end
@ -876,7 +912,7 @@ char* fat16_disk_label(const FAT16* fat, char* label_out)
} }
char* fat16_dispname(const FAT16_FILE* file, char* disp_out) char* ff_dispname(const FFILE* file, char* disp_out)
{ {
// Cannot get name for special files // Cannot get name for special files
if (file->type == FT_NONE || // not-yet-used directory location if (file->type == FT_NONE || // not-yet-used directory location
@ -926,7 +962,7 @@ char* fat16_dispname(const FAT16_FILE* file, char* disp_out)
} }
char* fat16_rawname(const char* disp_in, char* raw_out) char* ff_rawname(const char* disp_in, char* raw_out)
{ {
uint8_t name_c = 0, wr_c = 0; uint8_t name_c = 0, wr_c = 0;
bool filling = false; bool filling = false;
@ -1000,21 +1036,41 @@ char* fat16_rawname(const char* disp_in, char* raw_out)
} }
/** Write new file size (also to the disk). Does not allocate clusters. */ FSAVEPOS ff_savepos(const FFILE* file)
void fat16_resize(FAT16_FILE* file, uint32_t size) {
FSAVEPOS fsp;
fsp.clu = file->clu;
fsp.num = file->num;
fsp.cur_rel = file->cur_rel;
return fsp;
}
void ff_reopen(FFILE* file, const FSAVEPOS* pos)
{
open_file(file->fat, file, pos->clu, pos->num);
ff_seek(file, pos->cur_rel);
}
void ff_flush_file(FFILE* file)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = file->fat->dev; const BLOCKDEV* dev = file->fat->dev;
// Store open page
dev->flush();
// Store file size
// Find address for storing the size // Find address for storing the size
const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28); const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28);
file->size = size;
dev->seek(addr); dev->seek(addr);
dev->store(&size, 4); dev->store(&(file->size), 4);
// Seek to the end of the file, to make sure clusters are allocated // Seek to the end of the file, to make sure clusters are allocated
fat16_seek(file, size - 1); ff_seek(file, file->size - 1);
const uint16_t next = next_clu(fat, file->cur_clu); const uint16_t next = next_clu(fat, file->cur_clu);
if (next != 0xFFFF) if (next != 0xFFFF)
@ -1026,8 +1082,10 @@ void fat16_resize(FAT16_FILE* file, uint32_t size)
} }
} }
/** Low level no-check file delete and free */ /** Low level no-check file delete and free */
void delete_file_do(FAT16_FILE* file) void delete_file_do(FFILE* file)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
@ -1049,7 +1107,7 @@ void delete_file_do(FAT16_FILE* file)
/** Delete a simple file */ /** Delete a simple file */
bool fat16_rmfile(FAT16_FILE* file) bool ff_rmfile(FFILE* file)
{ {
switch (file->type) switch (file->type)
{ {
@ -1068,19 +1126,15 @@ bool fat16_rmfile(FAT16_FILE* file)
/** Delete an empty directory */ /** Delete an empty directory */
bool fat16_rmdir(FAT16_FILE* file) bool ff_rmdir(FFILE* file)
{ {
if (file->type != FT_SUBDIR) if (file->type != FT_SUBDIR)
return false; // not a subdirectory entry return false; // not a subdirectory entry
const FAT16* fat = file->fat; const FSAVEPOS orig = ff_savepos(file);
const uint16_t clu1 = file->clu;
const uint16_t num1 = file->num;
// Open the subdir // Open the subdir
if (!fat16_opendir(file)) if (!ff_opendir(file))
return false; // could not open return false; // could not open
// Look for valid files and subdirs in the directory // Look for valid files and subdirs in the directory
@ -1097,16 +1151,16 @@ bool fat16_rmdir(FAT16_FILE* file)
{ {
// Valid child file was found, aborting. // Valid child file was found, aborting.
// reopen original file // reopen original file
open_file(fat, file, clu1, num1); ff_reopen(file, &orig);
return false; return false;
} }
if (cnt < 2) cnt++; if (cnt < 2) cnt++;
} }
while (fat16_next(file)); while (ff_next(file));
// reopen original file // reopen original file
open_file(fat, file, clu1, num1); ff_reopen(file, &orig);
// and delete as ordinary file // and delete as ordinary file
delete_file_do(file); delete_file_do(file);
@ -1115,7 +1169,7 @@ bool fat16_rmdir(FAT16_FILE* file)
} }
bool fat16_delete(FAT16_FILE* file) bool ff_delete(FFILE* file)
{ {
switch (file->type) switch (file->type)
{ {
@ -1126,8 +1180,7 @@ bool fat16_delete(FAT16_FILE* file)
case FT_SUBDIR:; // semicolon needed to allow declaration after "case" case FT_SUBDIR:; // semicolon needed to allow declaration after "case"
// store original file location // store original file location
const uint16_t clu1 = file->clu; const FSAVEPOS orig = ff_savepos(file);
const uint16_t num1 = file->num;
// open the directory (skip "." and "..") // open the directory (skip "." and "..")
open_file(file->fat, file, file->clu_start, 2); open_file(file->fat, file, file->clu_start, 2);
@ -1135,34 +1188,32 @@ bool fat16_delete(FAT16_FILE* file)
// delete all children // delete all children
do do
{ {
if (!fat16_delete(file)) if (!ff_delete(file))
{ {
// failure // failure
// reopen original file // reopen original file
open_file(file->fat, file, clu1, num1); ff_reopen(file, &orig);
return false; return false;
} }
} }
while (fat16_next(file)); while (ff_next(file));
// go up and delete the dir // go up and delete the dir
open_file(file->fat, file, clu1, num1); ff_reopen(file, &orig);
return fat16_rmdir(file); return ff_rmdir(file);
default: default:
// try to delete as a regular file // try to delete as a regular file
return fat16_rmfile(file); return ff_rmfile(file);
} }
} }
bool fat16_parent(FAT16_FILE* file) bool ff_parent(FFILE* file)
{ {
const uint16_t clu1 = file->clu;
const uint16_t num1 = file->num;
// open second entry of the directory // open second entry of the directory
open_file(file->fat, file, file->clu, 1); open_file(file->fat, file, file->clu, 1);
const FSAVEPOS orig = ff_savepos(file);
// if it's a valid PARENT link, follow it. // if it's a valid PARENT link, follow it.
if (file->type == FT_PARENT) if (file->type == FT_PARENT)
@ -1174,7 +1225,7 @@ bool fat16_parent(FAT16_FILE* file)
{ {
// in root already? // in root already?
// reopen original file // reopen original file
open_file(file->fat, file, clu1, num1); ff_reopen(file, &orig);
return false; return false;
} }
} }

@ -1,28 +1,16 @@
#pragma once #pragma once
//
// Simple FAT16 library.
//
// To use it, implement BLOCKDEV functions
// and attach them to it's instance.
//
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/** #include "blockdev.h"
* Abstract block device interface
*
* Populate this with pointers to your I/O functions.
*/
typedef struct
{
// Sequential read
void (*load)(void* dest, const uint16_t len);
// Sequential write
void (*store)(const void* src, const uint16_t len);
// Sequential byte write
void (*write)(const uint8_t b);
// Sequential byte read
uint8_t (*read)(void);
// Absolute seek
void (*seek)(const uint32_t);
// Relative seek
void (*rseek)(const int16_t);
} BLOCKDEV;
// ------------------------------- // -------------------------------
@ -45,6 +33,15 @@ typedef enum
} FAT16_FT; } FAT16_FT;
/** "File address" for saving and restoring file */
typedef struct
{
uint16_t clu;
uint16_t num;
uint32_t cur_rel;
} FSAVEPOS;
// Include definitions of fully internal structs // Include definitions of fully internal structs
#include "fat16_internal.h" #include "fat16_internal.h"
@ -102,11 +99,31 @@ typedef struct __attribute__((packed))
// Pointer to the FAT16 handle. (internal) // Pointer to the FAT16 handle. (internal)
const FAT16* fat; const FAT16* fat;
} }
FAT16_FILE; FFILE;
/** Initialize the file system - store into "fat" */ /**
void fat16_init(const BLOCKDEV* dev, FAT16* fat); * Store modified file metadata and flush it to disk.
*/
void ff_flush_file(FFILE* file);
/**
* Save a file "position" into a struct, for later restoration.
* Cursor is also saved.
*/
FSAVEPOS ff_savepos(const FFILE* file);
/**
* Restore a file from a saved position.
*/
void ff_reopen(FFILE* file, const FSAVEPOS* pos);
/**
* Initialize the file system - store into "fat"
*/
bool ff_init(const BLOCKDEV* dev, FAT16* fat);
/** /**
@ -114,14 +131,17 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat);
* The file may be invalid (eg. a volume label, deleted etc), * The file may be invalid (eg. a volume label, deleted etc),
* or blank (type FT_NONE) if the filesystem is empty. * or blank (type FT_NONE) if the filesystem is empty.
*/ */
void fat16_root(const FAT16* fat, FAT16_FILE* file); void ff_root(const FAT16* fat, FFILE* file);
/** /**
* Resolve the disk label. * Resolve the disk label.
* That can be in the Boot Sector, or in the first root directory entry. * That can be in the Boot Sector, or in the first root directory entry.
*
* @param fat the FAT handle
* @param label_out string to store the label in. Should have at least 12 bytes.
*/ */
char* fat16_disk_label(const FAT16* fat, char* label_out); char* ff_disk_label(const FAT16* fat, char* label_out);
// ----------- FILE I/O ------------- // ----------- FILE I/O -------------
@ -131,21 +151,26 @@ char* fat16_disk_label(const FAT16* fat, char* label_out);
* Move file cursor to a position relative to file start * Move file cursor to a position relative to file start
* Returns false on I/O error (bad file, out of range...) * Returns false on I/O error (bad file, out of range...)
*/ */
bool fat16_seek(FAT16_FILE* file, uint32_t addr); bool ff_seek(FFILE* file, uint32_t addr);
/** /**
* Read bytes from file into memory * Read bytes from file into memory
* Returns false on I/O error (bad file, out of range...) * Returns number of bytes read, 0 on error.
*/ */
bool fat16_read(FAT16_FILE* file, void* target, uint32_t len); uint16_t ff_read(FFILE* file, void* target, uint16_t len);
/** /**
* Write into file at a "seek" position. * Write into file at a "seek" position.
* "seek" cursor must be within (0..filesize)
*/ */
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len); bool ff_write(FFILE* file, const void* source, uint32_t len);
/**
* Store a 0-terminated string at cursor.
*/
bool ff_write_str(FFILE* file, const char* source);
/** /**
@ -154,14 +179,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len);
* file ... open directory; new file is opened into this handle. * file ... open directory; new file is opened into this handle.
* name ... name of the new file, including extension * name ... name of the new file, including extension
*/ */
bool fat16_mkfile(FAT16_FILE* file, const char* name); bool ff_newfile(FFILE* file, const char* name);
/** /**
* Create a sub-directory of given name. * Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".." * Directory is allocated and populated with entries "." and ".."
*/ */
bool fat16_mkdir(FAT16_FILE* file, const char* name); bool ff_mkdir(FFILE* file, const char* name);
/** /**
@ -170,26 +195,26 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name);
* *
* Useful mainly for shrinking. * Useful mainly for shrinking.
*/ */
void fat16_resize(FAT16_FILE* file, uint32_t size); void set_file_size(FFILE* file, uint32_t size);
/** /**
* Delete a *FILE* and free it's clusters. * Delete a *FILE* and free it's clusters.
*/ */
bool fat16_rmfile(FAT16_FILE* file); bool ff_rmfile(FFILE* file);
/** /**
* Delete an empty *DIRECTORY* and free it's clusters. * Delete an empty *DIRECTORY* and free it's clusters.
*/ */
bool fat16_rmdir(FAT16_FILE* file); bool ff_rmdir(FFILE* file);
/** /**
* Delete a file or directory, even FT_LFN and FT_INVALID. * Delete a file or directory, even FT_LFN and FT_INVALID.
* Directories are deleted recursively (!) * Directories are deleted recursively (!)
*/ */
bool fat16_delete(FAT16_FILE* file); bool ff_delete(FFILE* file);
@ -197,55 +222,55 @@ bool fat16_delete(FAT16_FILE* file);
/** Go to previous file in the directory (false = no prev file) */ /** Go to previous file in the directory (false = no prev file) */
bool fat16_prev(FAT16_FILE* file); bool ff_prev(FFILE* file);
/** Go to next file in directory (false = no next file) */ /** Go to next file in directory (false = no next file) */
bool fat16_next(FAT16_FILE* file); bool ff_next(FFILE* file);
/** /**
* Open a subdirectory denoted by the file. * Open a subdirectory denoted by the file.
* Provided handle changes to the first entry of the directory. * Provided handle changes to the first entry of the directory.
*/ */
bool fat16_opendir(FAT16_FILE* dir); bool ff_opendir(FFILE* dir);
/** /**
* Open a parent directory. Fails in root. * Open a parent directory. Fails in root.
* Provided handle changes to the first entry of the parent directory. * Provided handle changes to the first entry of the parent directory.
*/ */
bool fat16_parent(FAT16_FILE* file); bool ff_parent(FFILE* file);
/** Jump to first file in this directory */ /** Jump to first file in this directory */
void fat16_first(FAT16_FILE* file); void ff_first(FFILE* file);
/** /**
* Find a file with given "display name" in this directory. * Find a file with given "display name" in this directory, and open it.
* If file is found, "dir" will contain it's handle. * If file is found, "dir" will contain it's handle.
* If file is NOT found, the handle points to the last entry of the directory. * If file is NOT found, the handle points to the last entry of the directory.
*/ */
bool fat16_find(FAT16_FILE* dir, const char* name); bool ff_open(FFILE* dir, const char* name);
// -------- FILE INSPECTION ----------- // -------- FILE INSPECTION -----------
/** Check if file is a valid entry, or long-name/label/deleted */ /** Check if file is a valid entry, or long-name/label/deleted */
bool fat16_is_regular(const FAT16_FILE* file); bool ff_is_regular(const FFILE* file);
/** /**
* Resolve a file name, trim spaces and add null terminator. * Resolve a file name, trim spaces and add null terminator.
* Returns the passed char*, or NULL on error. * Returns the passed char*, or NULL on error.
*/ */
char* fat16_dispname(const FAT16_FILE* file, char* disp_out); char* ff_dispname(const FFILE* file, char* disp_out);
/** /**
* Convert filename to zero-padded fixed length one * Convert filename to zero-padded fixed length one
* Returns the passed char*. * Returns the passed char*.
*/ */
char* fat16_rawname(const char* disp_in, char* raw_out); char* ff_rawname(const char* disp_in, char* raw_out);

@ -9,7 +9,6 @@
/** Boot Sector structure */ /** Boot Sector structure */
typedef struct __attribute__((packed)) typedef struct __attribute__((packed))
{ {
// Fields loaded directly from disk: // Fields loaded directly from disk:
// 13 bytes skipped // 13 bytes skipped

@ -81,26 +81,26 @@ int main()
// Initialize the FS // Initialize the FS
FAT16 fat; FAT16 fat;
fat16_init(&test, &fat); ff_init(&test, &fat);
FAT16_FILE file; FFILE file;
fat16_root(&fat, &file); ff_root(&fat, &file);
char str[12]; char str[12];
printf("Disk label: %s\n", fat16_disk_label(&fat, str)); printf("Disk label: %s\n", ff_disk_label(&fat, str));
do do
{ {
if (!fat16_is_regular(&file)) if (!ff_is_regular(&file))
continue; continue;
printf("File name: %s, %c, %d B, @ 0x%x\n", printf("File name: %s, %c, %d B, @ 0x%x\n",
fat16_dispname(&file, str), ff_dispname(&file, str),
file.type, file.size, file.clu_start); file.type, file.size, file.clu_start);
} }
while (fat16_next(&file)); while (ff_next(&file));
// fat16_root(&fat, &file); // fat16_root(&fat, &file);

Loading…
Cancel
Save