function to create a directory

master
Ondřej Hruška 9 years ago
parent 927488414a
commit 9b61123c20
  1. 2
      Makefile
  2. 346
      fat16.c
  3. 71
      fat16.h
  4. 59
      main.c
  5. BIN
      test

@ -1,7 +1,7 @@
all: main all: main
main: main.c main: main.c
gcc -std=gnu99 main.c fat16.c -o test -g gcc -Wall -std=gnu99 main.c fat16.c -o test -g
run: main run: main
./test ./test

@ -57,16 +57,16 @@ uint16_t read_fat(const FAT16* fat, const uint16_t cluster);
/** Find absolute address of first boot sector. Returns 0 on failure. */ /** Find absolute address of first boot sector. Returns 0 on failure. */
uint32_t find_bs(const BLOCKDEV* dev) uint32_t find_bs(const BLOCKDEV* dev)
{ {
// Reference structure: // Reference structure:
// //
// typedef struct __attribute__((packed)) { // typedef struct __attribute__((packed)) {
// uint8_t first_byte; // uint8_t first_byte;
// uint8_t start_chs[3]; // uint8_t start_chs[3];
// uint8_t partition_type; // uint8_t partition_type;
// uint8_t end_chs[3]; // uint8_t end_chs[3];
// uint32_t start_sector; // uint32_t start_sector;
// uint32_t length_sectors; // uint32_t length_sectors;
// } PartitionTable; // } PartitionTable;
uint16_t addr = 0x1BE + 4; // fourth byte of structure is the type. uint16_t addr = 0x1BE + 4; // fourth byte of structure is the type.
uint32_t tmp = 0; uint32_t tmp = 0;
@ -121,7 +121,8 @@ void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr)
if (info->total_sectors == 0) if (info->total_sectors == 0)
{ {
dev->load(&(info->total_sectors), 4); dev->load(&(info->total_sectors), 4);
} else }
else
{ {
dev->rseek(4); // tsl dev->rseek(4); // tsl
} }
@ -236,19 +237,18 @@ bool append_cluster(const FAT16* fat, const uint16_t clu)
void free_cluster_chain(const FAT16* fat, uint16_t clu) void free_cluster_chain(const FAT16* fat, uint16_t clu)
{ {
do { do
{
// get address of the next cluster // get address of the next cluster
const uint16_t clu2 = read_fat(fat, clu); const uint16_t clu2 = read_fat(fat, clu);
// mark cluster as unused // mark cluster as unused
write_fat(fat, clu, 0x0000); write_fat(fat, clu, 0x0000);
printf("Cluster free at %d\n", clu);
// advance // advance
clu = clu2; clu = clu2;
}
} while (clu != 0xFFFF); while (clu != 0xFFFF);
} }
@ -258,7 +258,8 @@ void free_cluster_chain(const FAT16* fat, uint16_t clu)
*/ */
bool dir_contains_file_raw(FAT16_FILE* dir, char* fname) bool dir_contains_file_raw(FAT16_FILE* dir, char* fname)
{ {
do { do
{
bool diff = false; bool diff = false;
for (uint8_t i = 0; i < 11; i++) for (uint8_t i = 0; i < 11; i++)
{ {
@ -271,7 +272,8 @@ bool dir_contains_file_raw(FAT16_FILE* dir, char* fname)
if (!diff) return true; if (!diff) return true;
} while (fat16_next(dir)); }
while (fat16_next(dir));
return false; return false;
} }
@ -290,7 +292,8 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
if (dir_cluster == 0) if (dir_cluster == 0)
{ {
addr = clu_addr(fat, dir_cluster) + num * 32; // root directory, max 512 entries. addr = clu_addr(fat, dir_cluster) + num * 32; // root directory, max 512 entries.
} else }
else
{ {
addr = clu_offs(fat, dir_cluster, num * 32); // cluster + N (wrapping to next cluster if needed) addr = clu_offs(fat, dir_cluster, num * 32); // cluster + N (wrapping to next cluster if needed)
} }
@ -307,7 +310,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
file->type = FT_FILE; file->type = FT_FILE;
switch(file->name[0]) switch (file->name[0])
{ {
case 0x00: case 0x00:
file->type = FT_NONE; file->type = FT_NONE;
@ -327,7 +330,8 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
{ {
// ".." directory // ".." directory
file->type = FT_PARENT; file->type = FT_PARENT;
} else }
else
{ {
// "." directory // "." directory
file->type = FT_SELF; file->type = FT_SELF;
@ -382,41 +386,43 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat)
*/ */
bool fat16_fseek(FAT16_FILE* file, uint32_t addr) bool fat16_fseek(FAT16_FILE* file, uint32_t addr)
{ {
const FAT16* fat = file->fat;
// Store as rel // Store as rel
file->cur_rel = addr; file->cur_rel = addr;
// Rewind and resolve abs, clu, ofs // Rewind and resolve abs, clu, ofs
file->cur_clu = file->clu_start; file->cur_clu = file->clu_start;
while (addr >= file->fat->bs.bytes_per_cluster) while (addr >= fat->bs.bytes_per_cluster)
{ {
uint32_t next; uint32_t next;
// Go to next cluster, allocate if needed // Go to next cluster, allocate if needed
do { do
next = next_clu(file->fat, file->cur_clu); {
next = next_clu(fat, file->cur_clu);
if (next == 0xFFFF) if (next == 0xFFFF)
{ {
// reached end of allocated space // reached end of allocated space
// add one more cluster // add one more cluster
if (!append_cluster(file->fat, file->cur_clu)) if (!append_cluster(fat, file->cur_clu))
{ {
return false; return false;
} }
printf("Allocating new cluster due to seek past EOF\n");
} }
} while(next == 0xFFFF); }
while (next == 0xFFFF);
file->cur_clu = next; file->cur_clu = next;
addr -= file->fat->bs.bytes_per_cluster; addr -= fat->bs.bytes_per_cluster;
} }
file->cur_abs = clu_addr(file->fat, file->cur_clu) + addr; file->cur_abs = clu_addr(fat, file->cur_clu) + addr;
file->cur_ofs = addr; file->cur_ofs = addr;
// Physically seek to that location // Physically seek to that location
file->fat->dev->seek(file->cur_abs); fat->dev->seek(file->cur_abs);
return true; return true;
} }
@ -427,7 +433,8 @@ bool fat16_fseek(FAT16_FILE* file, uint32_t addr)
*/ */
bool fat16_is_file_valid(const FAT16_FILE* file) bool fat16_is_file_valid(const FAT16_FILE* file)
{ {
switch (file->type) { switch (file->type)
{
case FT_FILE: case FT_FILE:
case FT_SUBDIR: case FT_SUBDIR:
case FT_SELF: case FT_SELF:
@ -444,18 +451,11 @@ bool fat16_is_file_valid(const FAT16_FILE* file)
bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len) bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len)
{ {
if (file->cur_abs == 0xFFFF) { if (file->cur_abs == 0xFFFF)
printf("File at 0xFFFF\n");
return false; // file at the end already return false; // 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
// Attempt to read more than what is available
printf("Attempt to read more than what is available\n");
return false;
}
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev; const BLOCKDEV* dev = fat->dev;
@ -493,7 +493,7 @@ bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len)
} }
bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len) bool fat16_fwrite(FAT16_FILE* file, 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;
@ -507,8 +507,10 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len)
{ {
const uint32_t pos_start = file->cur_rel; const uint32_t pos_start = file->cur_rel;
// Seek to the last position, using fseek to allocate clusters // Seek to the last position
if (!fat16_fseek(file, pos_start + len)) return false; // -> fseek will allocate clusters
if (!fat16_fseek(file, pos_start + len))
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 (file->cur_rel > file->size)
@ -532,8 +534,6 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len)
dev->write(0); dev->write(0);
} }
printf("Wrote %d filler zeros.\n", chunk);
// subtract from "needed" what was just placed // subtract from "needed" what was just placed
fill -= chunk; fill -= chunk;
@ -545,7 +545,7 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len)
} }
// Save new size // Save new size
fat16_set_file_size(file, pos_start + len); fat16_resize(file, pos_start + len);
// Seek back to where it was before // Seek back to where it was before
fat16_fseek(file, pos_start); fat16_fseek(file, pos_start);
@ -560,25 +560,25 @@ bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len)
// store the chunk // store the chunk
dev->seek(file->cur_abs); dev->seek(file->cur_abs);
dev->store(src, chunk); dev->store(source, chunk);
// advance cursors // advance cursors
file->cur_abs += chunk; file->cur_abs += chunk;
file->cur_rel += chunk; file->cur_rel += chunk;
file->cur_ofs += chunk; file->cur_ofs += chunk;
src += chunk; // advance the source pointer // Pointer arith!
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)
{ {
// advance to following cluster
file->cur_clu = next_clu(fat, file->cur_clu); file->cur_clu = next_clu(fat, file->cur_clu);
file->cur_abs = clu_addr(fat, file->cur_clu); file->cur_abs = clu_addr(fat, file->cur_clu);
file->cur_ofs = 0; file->cur_ofs = 0;
} }
printf("Stored %d bytes of data.\n", chunk);
// subtract written length // subtract written length
len -= chunk; len -= chunk;
} }
@ -597,20 +597,16 @@ bool fat16_next(FAT16_FILE* file)
if (file->clu == 0 && file->num >= fat->bs.root_entries) if (file->clu == 0 && file->num >= fat->bs.root_entries)
return false; // attempt to read outside root directory. return false; // attempt to read outside root directory.
uint32_t addr = clu_offs(fat, file->clu, (file->num + 1) * 32); const uint32_t addr = clu_offs(fat, file->clu, (file->num + 1) * 32);
if (addr == 0xFFFF) if (addr == 0xFFFF)
return false; // next file is out of the directory cluster return false; // next file is out of the directory cluster
// read first byte of the file entry; if zero, can't read (file is NONE) // read first byte of the file entry
// FIXME this may be a problem when creating a new file...?
uint8_t x;
dev->seek(addr); dev->seek(addr);
x = dev->read(); if (dev->read() == 0)
return false; // can't read (file is NONE)
if (x == 0)
return false;
open_file(fat, file, file->clu, file->num+1); open_file(fat, file, file->clu, file->num + 1);
return true; return true;
} }
@ -622,11 +618,7 @@ bool fat16_prev(FAT16_FILE* file)
if (file->num == 0) if (file->num == 0)
return false; // first file already return false; // first file already
open_file(file->fat, file, file->clu, file->num-1); open_file(file->fat, file, file->clu, file->num - 1);
/* // Skip bad files
if (!fat16_is_file_valid(file))
fat16_prev(file);*/
return true; return true;
} }
@ -639,7 +631,7 @@ void fat16_first(FAT16_FILE* file)
} }
/** Open a directory */ /** Open a directory denoted by the file. */
bool fat16_opendir(FAT16_FILE* file) bool fat16_opendir(FAT16_FILE* file)
{ {
// Don't open non-dirs and "." directory. // Don't open non-dirs and "." directory.
@ -651,7 +643,7 @@ bool fat16_opendir(FAT16_FILE* file)
} }
void fat16_open_root(const FAT16* fat, FAT16_FILE* file) void fat16_root(const FAT16* fat, FAT16_FILE* file)
{ {
open_file(fat, file, 0, 0); open_file(fat, file, 0, 0);
} }
@ -662,104 +654,170 @@ void fat16_open_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_file(FAT16_FILE* dir, const char* name) bool fat16_find(FAT16_FILE* dir, const char* name)
{ {
char fname[11]; char fname[11];
fat16_undisplay_name(name, fname); fat16_rawname(name, fname);
return dir_contains_file_raw(dir, fname); return dir_contains_file_raw(dir, fname);
} }
bool fat16_newfile(FAT16_FILE* dir, FAT16_FILE* file, const char* name) /** Go through a directory, and open first NONE or DELETED file. */
bool find_empty_file_slot(FAT16_FILE* file)
{ {
// Convert filename to zero padded raw string const uint16_t clu = file->clu;
char fname[11]; const FAT16* fat = file->fat;
fat16_undisplay_name(name, fname);
// Abort if file already exists
bool exists = dir_contains_file_raw(dir, fname);
fat16_first(dir); // rewind dir
if (exists) return false;
// Find free directory entry that can be used // Find free directory entry that can be used
uint16_t clu = dir->clu;
const FAT16* fat = dir->fat;
for (uint16_t num = 0; num < 0xFFFF; num++) for (uint16_t num = 0; num < 0xFFFF; num++)
{ {
// root directory has fewer entries, error if trying // root directory has fewer entries, error if trying
// to add one more. // to add one more.
if (dir->clu == 0 && num >= fat->bs.root_entries) if (file->clu == 0 && num >= fat->bs.root_entries)
return false; return false;
// Resolve addres of next file entry // Resolve addres of next file entry
uint32_t addr; uint32_t addr;
do { do
addr = clu_offs(fat, dir->clu, num * 32); {
addr = clu_offs(fat, file->clu, num * 32);
if (addr == 0xFFFF) if (addr == 0xFFFF)
{ {
// end of chain of allocated clusters for the directory // end of chain of allocated clusters for the directory
// append new cluster, return false on failure // append new cluster, return false on failure
if (!append_cluster(fat, dir->clu)) return false; if (!append_cluster(fat, file->clu)) return false;
} }
// if new cluster was just added, repeat. // if new cluster was just added, repeat.
} while (addr == 0xFFFF); }
while (addr == 0xFFFF);
// Open the file entry // Open the file entry
open_file(fat, file, clu, num); open_file(fat, file, clu, num);
// Check if can be overwritten // Check if can be overwritten
if (file->type == FT_DELETED || file->type == FT_NONE) if (file->type == FT_DELETED || file->type == FT_NONE)
{ {
const uint16_t newclu = alloc_cluster(fat); return true;
const uint32_t entrystart = clu_offs(fat, clu, num * 32); }
}
// store the file name return false; // not found.
fat->dev->seek(entrystart); }
// filename, without dor, zero-padded.
fat->dev->store(fname, 11);
fat->dev->write(0); // attributes /** 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;
// 10 reserved, 2+2 date & time const uint32_t entrystart = clu_offs(fat, file->clu, file->num * 32);
for (uint8_t i = 0; i < 14; i++)
{
fat->dev->write(0);
}
fat->dev->write16(newclu); // starting cluster // store the file name
dev->seek(entrystart);
dev->store(fname, 11);
// file size (uint32_t) // attributes
fat->dev->write16(0); dev->write(attribs);
fat->dev->write16(0);
// reopen file, load the information just written // 10 reserved, 2+2 date & time
open_file(fat, file, clu, num); // (could just skip, but better to fill with zeros)
return true; for (uint8_t i = 0; i < 14; i++)
} {
dev->write(0);
} }
return false;
// 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);
} }
char* fat16_volume_label(const FAT16* fat, char* str) bool fat16_mkfile(FAT16_FILE* file, const char* name)
{
// Convert filename to zero padded raw string
char fname[11];
fat16_rawname(name, fname);
// Abort if file already exists
bool exists = dir_contains_file_raw(file, fname);
fat16_first(file); // rewind dir
if (exists)
return false; // file already exists in the dir.
if (!find_empty_file_slot(file))
return false; // error finding a slot
// Write into the new slot
const uint16_t newclu = alloc_cluster(file->fat);
write_file_header(file, fname, 0, newclu);
return true;
}
/**
* Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".."
*/
bool fat16_mkdir(FAT16_FILE* file, const char* name)
{
// Convert filename to zero padded raw string
char fname[11];
fat16_rawname(name, fname);
// Abort if file already exists
bool exists = dir_contains_file_raw(file, fname);
fat16_first(file); // rewind dir
if (exists)
return false; // file already exusts in the dir.
if (!find_empty_file_slot(file))
return false; // error finding a slot
// Write into the new slot
const uint16_t newclu = alloc_cluster(file->fat);
write_file_header(file, fname, FA_DIR, newclu);
const uint32_t parent_clu = file->clu;
open_file(file->fat, file, file->clu_start, 0);
write_file_header(file, ". ", FA_DIR, newclu);
// Advance to next file slot
find_empty_file_slot(file);
write_file_header(file, ".. ", FA_DIR, parent_clu);
// rewind.
fat16_first(file);
return true;
}
char* fat16_disk_label(const FAT16* fat, char* label_out)
{ {
FAT16_FILE first; FAT16_FILE first;
fat16_open_root(fat, &first); fat16_root(fat, &first);
if (first.type == FT_LABEL) { if (first.type == FT_LABEL)
return fat16_display_name(&first, str); {
return fat16_dispname(&first, label_out);
} }
// find where spaces end // find where spaces end
uint8_t j = 10; int8_t j = 10;
for (; j >= 0; j--) for (; j >= 0; j--)
{ {
if (fat->bs.volume_label[j] != ' ') break; if (fat->bs.volume_label[j] != ' ') break;
@ -769,25 +827,25 @@ char* fat16_volume_label(const FAT16* fat, char* str)
uint8_t i; uint8_t i;
for (i = 0; i <= j; i++) for (i = 0; i <= j; i++)
{ {
str[i] = fat->bs.volume_label[i]; label_out[i] = fat->bs.volume_label[i];
} }
str[i] = 0; // ender label_out[i] = 0; // ender
return str; return label_out;
} }
char* fat16_display_name(const FAT16_FILE* file, char* str) char* fat16_dispname(const FAT16_FILE* 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
file->type == FT_DELETED || // deleted file entry file->type == FT_DELETED || // deleted file entry
file->attribs == 0x0F) // long name special entry (system, hidden) file->attribs == 0x0F) // long name special entry (system, hidden)
return NULL; return NULL;
// find first non-space // find first non-space
uint8_t j = 7; int8_t j = 7;
for (; j >= 0; j--) for (; j >= 0; j--)
{ {
if (file->name[j] != ' ') break; if (file->name[j] != ' ') break;
@ -798,37 +856,37 @@ char* fat16_display_name(const FAT16_FILE* file, char* str)
uint8_t i; uint8_t i;
for (i = 0; i <= j; i++) for (i = 0; i <= j; i++)
{ {
str[i] = file->name[i]; disp_out[i] = file->name[i];
} }
// directory entry, no extension // directory entry, no extension
if (file->type == FT_SUBDIR || file->type == FT_SELF || file->type == FT_PARENT) if (file->type == FT_SUBDIR || file->type == FT_SELF || file->type == FT_PARENT)
{ {
str[i] = 0; // end of string disp_out[i] = 0; // end of string
return str; return disp_out;
} }
// add a dot // add a dot
if (file->type != FT_LABEL) // volume label has no dot! if (file->type != FT_LABEL) // volume label has no dot!
str[i++] = '.'; disp_out[i++] = '.';
// Add extension chars // Add extension chars
for (j = 8; j < 11; j++, i++) for (j = 8; j < 11; j++, i++)
{ {
const char c = file->name[j]; const char c = file->name[j];
if (c == ' ') break; if (c == ' ') break;
str[i] = c; disp_out[i] = c;
} }
str[i] = 0; // end of string disp_out[i] = 0; // end of string
return str; return disp_out;
} }
char* fat16_undisplay_name(const char* name, char* fixed) char* fat16_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;
@ -836,9 +894,10 @@ char* fat16_undisplay_name(const char* name, char* fixed)
for (; wr_c < 11; wr_c++) for (; wr_c < 11; wr_c++)
{ {
// start filling with spaces if end of filename reached // start filling with spaces if end of filename reached
char c = name[name_c]; uint8_t c = disp_in[name_c];
// handle special rule for 0xE5 // handle special rule for 0xE5
if (name_c == 0 && c == 0xE5) { if (name_c == 0 && c == 0xE5)
{
c = 0x05; c = 0x05;
} }
@ -851,7 +910,7 @@ char* fat16_undisplay_name(const char* name, char* fixed)
if (c == '.') if (c == '.')
{ {
name_c++; // skip the dot name_c++; // skip the dot
c = name[name_c]; c = disp_in[name_c];
at_ext = true; at_ext = true;
} }
} }
@ -863,13 +922,14 @@ char* fat16_undisplay_name(const char* name, char* fixed)
if (!at_ext) if (!at_ext)
{ {
// try to advance past dot (if any) // try to advance past dot (if any)
while(true) while (true)
{ {
c = name[name_c++]; c = disp_in[name_c++];
if (c == 0) break; if (c == 0) break;
if (c == '.') { if (c == '.')
{
// read char PAST the dot // read char PAST the dot
c = name[name_c]; c = disp_in[name_c];
at_ext = true; at_ext = true;
break; break;
} }
@ -887,21 +947,21 @@ char* fat16_undisplay_name(const char* name, char* fixed)
if (!filling) if (!filling)
{ {
// copy char of filename // copy char of filename
fixed[wr_c] = name[name_c++]; raw_out[wr_c] = disp_in[name_c++];
} }
else else
{ {
// add a filler space // add a filler space
fixed[wr_c] = ' '; raw_out[wr_c] = ' ';
} }
} }
return fixed; return raw_out;
} }
/** Write new file size (also to the disk). Does not allocate clusters. */ /** Write new file size (also to the disk). Does not allocate clusters. */
void fat16_set_file_size(FAT16_FILE* file, uint32_t size) void fat16_resize(FAT16_FILE* file, uint32_t size)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;
const BLOCKDEV* dev = file->fat->dev; const BLOCKDEV* dev = file->fat->dev;
@ -919,8 +979,6 @@ void fat16_set_file_size(FAT16_FILE* file, uint32_t size)
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)
{ {
printf("Trimming file clusters\n");
free_cluster_chain(fat, next); free_cluster_chain(fat, next);
// Mark that there's no further clusters // Mark that there's no further clusters
@ -929,7 +987,7 @@ void fat16_set_file_size(FAT16_FILE* file, uint32_t size)
} }
void fat16_delete_file(FAT16_FILE* file) void fat16_delete(FAT16_FILE* file)
{ {
const FAT16* fat = file->fat; const FAT16* fat = file->fat;

@ -1,7 +1,8 @@
#pragma once #pragma once
/** Abstract block device interface */ /** Abstract block device interface */
typedef struct { typedef struct
{
// Sequential read // Sequential read
void (*load)(void* dest, const uint16_t len); void (*load)(void* dest, const uint16_t len);
// Sequential write // Sequential write
@ -24,7 +25,8 @@ typedef struct {
// ------------------------------- // -------------------------------
/** file types (values don't matter) */ /** file types (values don't matter) */
typedef enum { typedef enum
{
FT_NONE = '-', FT_NONE = '-',
FT_DELETED = 'x', FT_DELETED = 'x',
FT_SUBDIR = 'D', FT_SUBDIR = 'D',
@ -46,7 +48,8 @@ typedef enum {
/** Boot Sector structure - INTERNAL! */ /** Boot Sector structure - INTERNAL! */
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed))
{
// Fields loaded directly from disk: // Fields loaded directly from disk:
@ -66,11 +69,13 @@ typedef struct __attribute__((packed)) {
uint32_t bytes_per_cluster; uint32_t bytes_per_cluster;
} Fat16BootSector; }
Fat16BootSector;
/** FAT filesystem handle - private fields! */ /** FAT filesystem handle - private fields! */
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed))
{
// Backing block device // Backing block device
const BLOCKDEV* dev; const BLOCKDEV* dev;
@ -85,12 +90,13 @@ typedef struct __attribute__((packed)) {
// Boot sector data struct // Boot sector data struct
Fat16BootSector bs; Fat16BootSector bs;
} FAT16; }
FAT16;
/** File handle struct */ /** File handle struct */
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed))
{
// Fields loaded directly from disk: // Fields loaded directly from disk:
uint8_t name[11]; // Starting 0x05 converted to 0xE5, other "magic chars" left intact uint8_t name[11]; // Starting 0x05 converted to 0xE5, other "magic chars" left intact
@ -117,12 +123,14 @@ typedef struct __attribute__((packed)) {
// pointer to FAT // pointer to FAT
const FAT16* fat; const FAT16* fat;
} FAT16_FILE; }
FAT16_FILE;
/** Initialize a filesystem */ /** Initialize a filesystem */
void fat16_init(const BLOCKDEV* dev, FAT16* fat); void fat16_init(const BLOCKDEV* dev, FAT16* fat);
/** /**
* Open the first file of the root directory. * Open the first file of the root directory.
* The file may be invalid (eg. a volume label, deleted etc), * The file may be invalid (eg. a volume label, deleted etc),
@ -130,12 +138,13 @@ void fat16_init(const BLOCKDEV* dev, FAT16* fat);
* *
* Either way, the prev and next functions will work as expected. * Either way, the prev and next functions will work as expected.
*/ */
void fat16_open_root(const FAT16* fat, FAT16_FILE* file); void fat16_root(const FAT16* fat, FAT16_FILE* file);
/** /**
* Resolve volume label. * Resolve the disk label.
*/ */
char* fat16_volume_label(const FAT16* fat, char* str); char* fat16_disk_label(const FAT16* fat, char* label_out);
// ----------- FILE I/O ------------- // ----------- FILE I/O -------------
@ -154,29 +163,39 @@ bool fat16_fseek(FAT16_FILE* file, uint32_t addr);
*/ */
bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len); bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len);
/** /**
* Write into file at a "seek" position. * Write into file at a "seek" position.
* "seek" cursor must be within (0..filesize) * "seek" cursor must be within (0..filesize)
*/ */
bool fat16_fwrite(FAT16_FILE* file, void* src, uint32_t len); bool fat16_fwrite(FAT16_FILE* file, void* source, uint32_t len);
/** /**
* Create a new file in given folder * Create a new file in given folder
* *
* directory ... parent folder's first entry * file ... open directory; new file is opened into this handle.
* file ... where to store info about newly opened file
* name ... name of the new file, including extension * name ... name of the new file, including extension
*/ */
bool fat16_newfile(FAT16_FILE* directory, FAT16_FILE* file, const char* name); bool fat16_mkfile(FAT16_FILE* file, const char* name);
/**
* Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".."
*/
bool fat16_mkdir(FAT16_FILE* file, const char* name);
/** /**
* Write new file size (also to the disk). * Write new file size (also to the disk).
* Allocates / frees needed clusters, does not erase them. * Allocates / frees needed clusters, does not erase them.
*/ */
void fat16_set_file_size(FAT16_FILE* file, uint32_t size); void fat16_resize(FAT16_FILE* file, uint32_t size);
/** Delete a file entry and free clusters. Does NOT descend into subdirectories. */ /** Delete a file entry and free clusters. Does NOT descend into subdirectories. */
void fat16_delete_file(FAT16_FILE* file); void fat16_delete(FAT16_FILE* file);
// --------- NAVIGATION ------------ // --------- NAVIGATION ------------
@ -184,21 +203,28 @@ void fat16_delete_file(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 fat16_prev(FAT16_FILE* 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 fat16_next(FAT16_FILE* file);
/** Open a directory (file is a directory entry) */
/**
* Open a subdirectory denoted by the file.
* Provided handle changes to first entry of the directory.
*/
bool fat16_opendir(FAT16_FILE* file); bool fat16_opendir(FAT16_FILE* file);
/** Rewind to first file in directory */ /** Rewind to first file in directory */
void fat16_first(FAT16_FILE* file); void fat16_first(FAT16_FILE* file);
/** /**
* Find a file with given "display name" in this directory. * Find a file with given "display name" in this directory.
* 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_file(FAT16_FILE* dir, const char* name); bool fat16_find(FAT16_FILE* dir, const char* name);
// -------- FILE INSPECTION ----------- // -------- FILE INSPECTION -----------
@ -211,11 +237,12 @@ bool fat16_is_file_valid(const FAT16_FILE* 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_display_name(const FAT16_FILE* file, char* str); char* fat16_dispname(const FAT16_FILE* 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_undisplay_name(const char* name, char* fixed); char* fat16_rawname(const char* disp_in, char* raw_out);

@ -90,12 +90,8 @@ void test_close()
// --- testing --- // --- testing ---
int main(int argc, char const *argv[]) int main()
{ {
uint32_t i32;
uint16_t i16;
uint8_t i8;
test_open(); test_open();
// Initialize the FS // Initialize the FS
@ -103,22 +99,57 @@ int main(int argc, char const *argv[])
fat16_init(&test, &fat); fat16_init(&test, &fat);
FAT16_FILE file; FAT16_FILE file;
fat16_open_root(&fat, &file); fat16_root(&fat, &file);
char str[12]; char str[12];
printf("Disk label: %s\n", fat16_volume_label(&fat, str)); printf("Disk label: %s\n", fat16_disk_label(&fat, str));
do { do
{
if (!fat16_is_file_valid(&file)) continue; if (!fat16_is_file_valid(&file)) continue;
printf("File name: %s, %c, %d B, @ 0x%x\n", printf("File name: %s, %c, %d B, @ 0x%x\n",
fat16_display_name(&file, str), fat16_dispname(&file, str),
file.type, file.size, file.clu_start); file.type, file.size, file.clu_start);
} while (fat16_next(&file)); }
while (fat16_next(&file));
fat16_open_root(&fat, &file);
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);
}
}
}
//fat16_mkfile(&file, "banana.exe");
//fat16_fwrite(&file, "THIS IS A STRING STORED IN A FILE CALLED BANANA!\n", 49);
// fat16_find(&file, "banana.exe");
// char m[49];
// fat16_fread(&file, m, 49);
// printf("%.49s\n", m);
//fat16_mkdir(&file, "FOLDER2");
// bool found = fat16_find_file(&file, "NEW_FILE.DAT"); // bool found = fat16_find_file(&file, "NEW_FILE.DAT");
// //

BIN
test

Binary file not shown.
Loading…
Cancel
Save