Skip to content
Snippets Groups Projects

feat(fatfs): implement opendir & readdir

Merged swym requested to merge swym/firmware:dir into master
All threads resolved!
Files
6
@@ -48,6 +48,7 @@ struct FatObject {
@@ -48,6 +48,7 @@ struct FatObject {
FIL file;
FIL file;
DIR dir;
DIR dir;
};
};
 
FILINFO *finfo;
};
};
struct EpicFileSystem {
struct EpicFileSystem {
@@ -65,6 +66,9 @@ static bool globalLockAccquire();
@@ -65,6 +66,9 @@ static bool globalLockAccquire();
static void globalLockRelease();
static void globalLockRelease();
static void efs_close_all(EpicFileSystem *fs);
static void efs_close_all(EpicFileSystem *fs);
 
/**
 
* if EPICSTAT_NONE is passed to `expected`, the type is not checked.
 
*/
static bool efs_get_opened(
static bool efs_get_opened(
EpicFileSystem *fs,
EpicFileSystem *fs,
int i,
int i,
@@ -73,6 +77,19 @@ static bool efs_get_opened(
@@ -73,6 +77,19 @@ static bool efs_get_opened(
int *rc
int *rc
);
);
 
static bool
 
efs_get_new(EpicFileSystem *fs, uint32_t *idx, struct FatObject **obj, int *rc);
 
 
static int efs_obj_init(
 
EpicFileSystem *fs,
 
struct FatObject *obj,
 
uint32_t index,
 
enum epic_stat_type type
 
);
 
 
static void efs_obj_deinit(EpicFileSystem *fs, struct FatObject *obj);
 
static void efs_init_stat(struct epic_stat *stat, FILINFO *finfo);
 
static EpicFileSystem s_globalFileSystem;
static EpicFileSystem s_globalFileSystem;
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
#if (EPIC_FAT_STATIC_SEMAPHORE == 1)
@@ -225,8 +242,10 @@ static bool efs_get_opened(
@@ -225,8 +242,10 @@ static bool efs_get_opened(
generation >= EPIC_FAT_FD_MAX_GENERATION) {
generation >= EPIC_FAT_FD_MAX_GENERATION) {
return false;
return false;
}
}
if (fs->pool[index].type != expected ||
if (fs->pool[index].generation != generation) {
fs->pool[index].generation != generation) {
return false;
 
}
 
if (expected != EPICSTAT_NONE && fs->pool[index].type != expected) {
return false;
return false;
}
}
@@ -235,6 +254,58 @@ static bool efs_get_opened(
@@ -235,6 +254,58 @@ static bool efs_get_opened(
return true;
return true;
}
}
 
static bool
 
efs_get_new(EpicFileSystem *fs, uint32_t *idx, struct FatObject **obj, int *rc)
 
{
 
uint32_t index;
 
 
*obj = NULL;
 
*rc = 0;
 
*idx = 0;
 
 
//find free object to use
 
for (index = 0; index < EPIC_FAT_MAX_OPENED; ++index) {
 
if (fs->pool[index].type == EPICSTAT_NONE) {
 
break;
 
}
 
}
 
if (index == EPIC_FAT_MAX_OPENED) {
 
*rc = -s_libffToErrno[FR_TOO_MANY_OPEN_FILES];
 
return false;
 
}
 
 
*obj = &fs->pool[index];
 
return true;
 
}
 
 
static int efs_obj_init(
 
EpicFileSystem *fs,
 
struct FatObject *obj,
 
uint32_t index,
 
enum epic_stat_type type
 
) {
 
uint32_t generation;
 
 
generation = fs->generationCount++;
 
if (generation == EPIC_FAT_FD_MAX_GENERATION) {
 
fs->generationCount = 1;
 
}
 
obj->type = type;
 
obj->generation = generation;
 
obj->finfo = NULL;
 
 
return EPIC_FAT_FD(index, generation);
 
}
 
 
static void efs_obj_deinit(EpicFileSystem *fs, struct FatObject *obj)
 
{
 
LOG_DEBUG("efs", "freeing FILINFO %p", obj->finfo);
 
free(obj->finfo);
 
obj->finfo = NULL;
 
obj->type = EPICSTAT_NONE;
 
obj->generation = 0;
 
}
 
/* here we're trying to mirror glibc's behaviour:
/* here we're trying to mirror glibc's behaviour:
* any combination of rwax parses but only the first of those flags wins:
* any combination of rwax parses but only the first of those flags wins:
* - rw, ra, rr all open read-only
* - rw, ra, rr all open read-only
@@ -282,58 +353,45 @@ static inline bool parse_mode(const char *mstring, int *mode)
@@ -282,58 +353,45 @@ static inline bool parse_mode(const char *mstring, int *mode)
int efs_open(EpicFileSystem *fs, const char *filename, const char *modeString)
int efs_open(EpicFileSystem *fs, const char *filename, const char *modeString)
{
{
struct FatObject *o = NULL;
struct FatObject *o = NULL;
uint32_t index, generation;
uint32_t index;
int mode = 0;
int mode = 0;
int res;
int res;
//find free object to use
for (index = 0; index < EPIC_FAT_MAX_OPENED; ++index) {
if (fs->pool[index].type == EPICSTAT_NONE) {
break;
}
}
if (index == EPIC_FAT_MAX_OPENED) {
return -s_libffToErrno[FR_TOO_MANY_OPEN_FILES];
}
generation = fs->generationCount++;
if (generation == EPIC_FAT_FD_MAX_GENERATION) {
fs->generationCount = 1;
}
o = &fs->pool[index];
if (!parse_mode(modeString, &mode)) {
if (!parse_mode(modeString, &mode)) {
return -EINVAL;
return -EINVAL;
}
}
 
if (!efs_get_new(fs, &index, &o, &res)) {
 
return res;
 
}
 
res = f_open(&o->file, filename, mode);
res = f_open(&o->file, filename, mode);
if (res != FR_OK) {
if (res != FR_OK) {
return -s_libffToErrno[res];
return -s_libffToErrno[res];
}
}
o->type = EPICSTAT_FILE;
o->generation = generation;
// for 'a' mode, we must begin at the end of the file
// for 'a' mode, we must begin at the end of the file
if ((mode & FA_OPEN_APPEND) != 0) {
if ((mode & FA_OPEN_APPEND) != 0) {
f_lseek(&o->file, f_size(&o->file));
f_lseek(&o->file, f_size(&o->file));
}
}
return EPIC_FAT_FD(index, generation);
return efs_obj_init(fs, o, index, EPICSTAT_FILE);
}
}
int efs_close(EpicFileSystem *fs, int fd)
int efs_close(EpicFileSystem *fs, int fd)
{
{
int res;
int res;
struct FatObject *o;
struct FatObject *o;
if (efs_get_opened(fs, fd, EPICSTAT_FILE, &o, &res)) {
if (efs_get_opened(fs, fd, EPICSTAT_NONE, &o, &res)) {
res = f_close(&o->file);
if (o->type == EPICSTAT_FILE) {
 
res = f_close(&o->file);
 
} else {
 
res = f_closedir(&o->dir);
 
}
if (res != FR_OK) {
if (res != FR_OK) {
return -s_libffToErrno[res];
return -s_libffToErrno[res];
}
}
efs_obj_deinit(fs, o);
o->type = EPICSTAT_NONE;
o->generation = 0;
}
}
return res;
return res;
}
}
@@ -346,13 +404,12 @@ void efs_close_all(EpicFileSystem *fs)
@@ -346,13 +404,12 @@ void efs_close_all(EpicFileSystem *fs)
f_close(&fs->pool[i].file);
f_close(&fs->pool[i].file);
break;
break;
case EPICSTAT_DIR:
case EPICSTAT_DIR:
//NYI
f_closedir(&fs->pool[i].dir);
break;
break;
case EPICSTAT_NONE:
case EPICSTAT_NONE:
break;
break;
}
}
fs->pool[i].type = EPICSTAT_NONE;
efs_obj_deinit(fs, &fs->pool[i]);
fs->pool[i].generation = 0;
}
}
}
}
@@ -440,18 +497,75 @@ int efs_tell(EpicFileSystem *fs, int fd)
@@ -440,18 +497,75 @@ int efs_tell(EpicFileSystem *fs, int fd)
return res;
return res;
}
}
 
static void efs_init_stat(struct epic_stat *stat, FILINFO *finfo)
 
{
 
if (finfo->fname[0] != 0) {
 
if (finfo->fattrib & AM_DIR) {
 
stat->type = EPICSTAT_DIR;
 
} else {
 
stat->type = EPICSTAT_FILE;
 
}
 
stat->name = finfo->fname;
 
} else {
 
stat->name = NULL;
 
stat->type = EPICSTAT_NONE;
 
}
 
}
 
int efs_stat(EpicFileSystem *fs, const char *filename, struct epic_stat *stat)
int efs_stat(EpicFileSystem *fs, const char *filename, struct epic_stat *stat)
{
{
int res = 0;
int res = 0;
FILINFO finfo;
static FILINFO finfo;
res = f_stat(filename, &finfo);
res = f_stat(filename, &finfo);
if (res == 0) {
if (res == 0) {
if (finfo.fattrib & AM_DIR) {
efs_init_stat(stat, &finfo);
stat->type = EPICSTAT_DIR;
}
} else {
return -s_libffToErrno[res];
stat->type = EPICSTAT_FILE;
}
 
 
int efs_opendir(EpicFileSystem *fs, const char *path)
 
{
 
int res;
 
struct FatObject *o;
 
uint32_t index;
 
 
if (efs_get_new(fs, &index, &o, &res)) {
 
res = f_opendir(&o->dir, path);
 
if (res != FR_OK) {
 
return -s_libffToErrno[res];
}
}
 
return efs_obj_init(fs, o, index, EPICSTAT_DIR);
}
}
 
return res;
 
}
 
 
int efs_readdir(EpicFileSystem *fs, int fd, struct epic_stat *stat)
 
{
 
int res;
 
struct FatObject *o;
 
if (efs_get_opened(fs, fd, EPICSTAT_DIR, &o, &res)) {
 
//f_tell simply accesses fp->fptr so no errors are expected - return directly
 
FILINFO *finfo = NULL;
 
if (stat) {
 
finfo = o->finfo;
 
if (finfo == NULL) {
 
LOG_DEBUG("efs", "allocating FILINFO");
 
finfo = (FILINFO *)malloc(sizeof(FILINFO));
 
memset(finfo, 0, sizeof(FILINFO));
 
o->finfo = finfo;
 
}
 
}
 
res = f_readdir(&o->dir, finfo);
 
if (res == FR_OK && stat) {
 
efs_init_stat(stat, finfo);
 
}
 
}
 
return res;
 
}
 
 
int efs_unlink(EpicFileSystem *fs, const char *path)
 
{
 
int res = f_unlink(path);
return -s_libffToErrno[res];
return -s_libffToErrno[res];
}
}
Loading