fat16_parent, func to rm directory

master
Ondřej Hruška 10 years ago
parent 9b61123c20
commit 228099e1d4
  1. 2
      .gitignore
  2. 274
      fat16.c
  3. 20
      fat16.h
  4. 59
      main.c
  5. BIN
      test

2
.gitignore vendored

@ -31,6 +31,8 @@
# Debug files # Debug files
*.dSYM/ *.dSYM/
./test
# Code::Blocks garbage # Code::Blocks garbage
*.depend *.depend
*.layout *.layout

@ -51,6 +51,9 @@ void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value);
/** Read a value from FAT */ /** Read a value from FAT */
uint16_t read_fat(const FAT16* fat, const uint16_t cluster); 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 ========= // =========== 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; file->type = FT_FILE;
switch (file->name[0]) const uint8_t c = file->name[0];
switch (c)
{ {
case 0x00: case 0x00:
file->type = FT_NONE; file->type = FT_NONE;
@ -339,8 +343,15 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
break; break;
default: default:
if (c < 32)
{
file->type = FT_INVALID; // File is corrupt, treat it as invalid
}
else
{
file->type = FT_FILE; file->type = FT_FILE;
} }
}
// handle subdir, label // handle subdir, label
if (file->attribs & FA_DIR && file->type == FT_FILE) if (file->attribs & FA_DIR && file->type == FT_FILE)
@ -353,7 +364,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
} }
else if (file->attribs == 0x0F) 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 // 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 ================= // =============== PUBLIC FUNCTION IMPLEMENTATIONS =================
/** Initialize a FAT16 handle */ /** Initialize a FAT16 handle */
@ -661,86 +771,6 @@ bool fat16_find(FAT16_FILE* dir, const char* name)
return dir_contains_file_raw(dir, fname); 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) bool fat16_mkfile(FAT16_FILE* file, const char* name)
{ {
// Convert filename to zero padded raw string // 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
delete_file_do(file);
return true;
}
void fat16_delete(FAT16_FILE* file) /** 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; const FAT16* fat = file->fat;
// seek to file record const uint16_t dir_clu = file->clu;
fat->dev->seek(clu_offs(fat, file->clu, file->num * 32)); const uint16_t dir_num = file->num;
// mark as deleted // Look for valid files and subdirs in the directory
fat->dev->write(0xE5); // "deleted" mark if (!fat16_opendir(file))
return false; // could not open
// free allocated clusters uint8_t cnt = 0;
free_cluster_chain(fat, file->clu_start); 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;
}
} }

@ -33,6 +33,7 @@ typedef enum
FT_PARENT = 'P', FT_PARENT = 'P',
FT_LABEL = 'L', FT_LABEL = 'L',
FT_LFN = '~', FT_LFN = '~',
FT_INVALID = 'i', // not recognized weird file
FT_SELF = '.', FT_SELF = '.',
FT_FILE = 'F' FT_FILE = 'F'
} FAT16_FT; } FAT16_FT;
@ -194,8 +195,18 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name);
void fat16_resize(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. */ /**
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 ------------ // --------- NAVIGATION ------------
@ -214,6 +225,11 @@ bool fat16_next(FAT16_FILE* file);
*/ */
bool fat16_opendir(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 */ /** Rewind to first file in directory */
void fat16_first(FAT16_FILE* file); void fat16_first(FAT16_FILE* file);

@ -118,31 +118,46 @@ int main()
fat16_root(&fat, &file); fat16_root(&fat, &file);
if (fat16_find(&file, "FOLDER")) // if (fat16_find(&file, "FOLDER"))
{ // {
if (fat16_opendir(&file)) // if (fat16_opendir(&file))
{ // {
printf("Listing FOLDER:\n"); // printf("Listing FOLDER:\n");
do // do
{ // {
printf("File name: %s, %c, %d B, @ 0x%x\n", // printf("File name: %s, %c, %d B, @ 0x%x\n",
fat16_dispname(&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));
if (fat16_find(&file, "banana.exe")) // char m[49];
{
char m[49]; // if (fat16_find(&file, "banana.exe"))
fat16_fread(&file, m, 49); // {
printf("%.49s\n", m); // fat16_fread(&file, m, 49);
} // printf("%.49s\n", m);
} // }
}
// fat16_rmfile(&file);
//fat16_mkfile(&file, "banana.exe"); // if (fat16_parent(&file)) {
//fat16_fwrite(&file, "THIS IS A STRING STORED IN A FILE CALLED BANANA!\n", 49); // printf("Current file: %s\n", fat16_dispname(&file, m));
// }
// printf("Found? %d\n", fat16_find(&file, "FOLDER2"));
// printf("Deleted? %d\n", fat16_rmdir(&file));
// }
// }
// 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"); // fat16_find(&file, "banana.exe");
// char m[49]; // char m[49];

BIN
test

Binary file not shown.
Loading…
Cancel
Save