fat16_parent, func to rm directory

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

2
.gitignore vendored

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

@ -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;
}
}

@ -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);

@ -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];

BIN
test

Binary file not shown.
Loading…
Cancel
Save